VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideo.cpp@ 31827

Last change on this file since 31827 was 31827, checked in by vboxsync, 14 years ago

VBoxVideo: Report legacy VGA resources, do not try to claim conflicting PCI resources.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 133.3 KB
Line 
1/*
2 * VirtualBox Video miniport driver for NT/2k/XP
3 *
4 * Based on DDK sample code.
5 *
6 * Copyright (C) 2006-2007 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include "VBoxVideo.h"
18#include "Helper.h"
19
20#include <iprt/log.h>
21#include <VBox/VMMDev.h>
22#include <VBox/VBoxGuest.h>
23#include <VBox/VBoxVideo.h>
24
25#include <VBox/VBoxGuestLib.h>
26#include <VBoxDisplay.h>
27
28#if _MSC_VER >= 1400 /* bird: MS fixed swprintf to be standard-conforming... */
29#define _INC_SWPRINTF_INL_
30extern "C" int __cdecl swprintf(wchar_t *, const wchar_t *, ...);
31#endif
32#include <wchar.h>
33
34#include "vboxioctl.h"
35
36
37static WCHAR VBoxChipType[] = L"VBOX";
38static WCHAR VBoxDACType[] = L"Integrated RAMDAC";
39static WCHAR VBoxAdapterString[] = L"VirtualBox Video Adapter";
40static WCHAR VBoxBiosString[] = L"Version 0xB0C2 or later";
41
42VIDEO_ACCESS_RANGE VGARanges[] = {
43 { 0x000003B0, 0x00000000, 0x0000000C, 1, 1, 1, 0 }, /* 0x3B0-0x3BB */
44 { 0x000003C0, 0x00000000, 0x00000020, 1, 1, 1, 0 }, /* 0x3C0-0x3DF */
45 { 0x000A0000, 0x00000000, 0x00020000, 0, 0, 1, 0 }, /* 0xA0000-0xBFFFF */
46};
47/*
48 * Globals for the last custom resolution set. This is important
49 * for system startup so that we report the last currently set
50 * custom resolution and Windows can use it again.
51 */
52#ifndef VBOX_WITH_MULTIMONITOR_FIX
53ULONG gCustomXRes = 0;
54ULONG gCustomYRes = 0;
55ULONG gCustomBPP = 0;
56#endif /* !VBOX_WITH_MULTIMONITOR_FIX */
57
58int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult);
59
60#ifndef VBOXWDDM
61ULONG DriverEntry(IN PVOID Context1, IN PVOID Context2)
62{
63 VIDEO_HW_INITIALIZATION_DATA InitData;
64 ULONG rc;
65
66 dprintf(("VBoxVideo::DriverEntry. Built %s %s\n", __DATE__, __TIME__));
67
68 VideoPortZeroMemory(&InitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));
69 InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
70 InitData.HwFindAdapter = VBoxVideoFindAdapter;
71 InitData.HwInitialize = VBoxVideoInitialize;
72#if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL)
73 InitData.HwInterrupt = VBoxVideoInterrupt;
74#else
75 InitData.HwInterrupt = NULL;
76#endif
77 InitData.HwStartIO = VBoxVideoStartIO;
78 InitData.HwResetHw = VBoxVideoResetHW;
79 InitData.HwDeviceExtensionSize = 0;
80 // nowhere documented but without the following line, NT4 SP0 will choke
81 InitData.AdapterInterfaceType = PCIBus;
82 InitData.HwGetPowerState = VBoxVideoGetPowerState;
83 InitData.HwSetPowerState = VBoxVideoSetPowerState;
84 InitData.HwGetVideoChildDescriptor = VBoxVideoGetChildDescriptor;
85 InitData.HwDeviceExtensionSize = sizeof(DEVICE_EXTENSION);
86 // report legacy VGA resource ranges
87 InitData.HwLegacyResourceList = VGARanges;
88 InitData.HwLegacyResourceCount = sizeof(VGARanges) / sizeof(VGARanges[0]);
89
90 // our DDK is at the Win2k3 level so we have to take special measures
91 // for backwards compatibility
92 switch (vboxQueryWinVersion())
93 {
94 case WINNT4:
95 dprintf(("VBoxVideo::DriverEntry: WINNT4\n"));
96 InitData.HwInitDataSize = SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA;
97 break;
98 case WIN2K:
99 dprintf(("VBoxVideo::DriverEntry: WIN2K\n"));
100 InitData.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
101 break;
102 }
103 rc = VideoPortInitialize(Context1, Context2, &InitData, NULL);
104
105 dprintf(("VBoxVideo::DriverEntry: returning with rc = 0x%x\n", rc));
106 return rc;
107}
108
109/*+++
110
111Routine Description:
112
113 This routine is used to read back various registry values.
114
115Arguments:
116
117 HwDeviceExtension
118 Supplies a pointer to the miniport's device extension.
119
120 Context
121 Context value passed to the get registry parameters routine.
122 If this is not null assume it's a ULONG* and save the data value in it.
123
124 ValueName
125 Name of the value requested.
126
127 ValueData
128 Pointer to the requested data.
129
130 ValueLength
131 Length of the requested data.
132
133Return Value:
134
135 If the variable doesn't exist return an error,
136 else if a context is supplied assume it's a PULONG and fill in the value
137 and return no error, else if the value is non-zero return an error.
138
139---*/
140VP_STATUS VBoxRegistryCallback(PVOID HwDeviceExtension, PVOID Context,
141 PWSTR ValueName, PVOID ValueData, ULONG ValueLength)
142{
143 //dprintf(("VBoxVideo::VBoxRegistryCallback: Context: %p, ValueName: %S, ValueData: %p, ValueLength: %d\n",
144 // Context, ValueName, ValueData, ValueLength));
145 if (ValueLength)
146 {
147 if (Context)
148 *(ULONG *)Context = *(PULONG)ValueData;
149 else if (*((PULONG)ValueData) != 0)
150 return ERROR_INVALID_PARAMETER;
151 return NO_ERROR;
152 }
153 else
154 return ERROR_INVALID_PARAMETER;
155}
156
157VP_STATUS VBoxVideoCmnRegQueryDword(IN VBOXCMNREG Reg, PWSTR pName, uint32_t *pVal)
158{
159 return VideoPortGetRegistryParameters(Reg, pName, FALSE, VBoxRegistryCallback, pVal);
160}
161
162VP_STATUS VBoxVideoCmnRegSetDword(IN VBOXCMNREG Reg, PWSTR pName, uint32_t Val)
163{
164 return VideoPortSetRegistryParameters(Reg, pName, &Val, sizeof(Val));
165}
166
167#endif /* #ifndef VBOXWDDM */
168
169/*
170 * Global list of supported standard video modes. It will be
171 * filled dynamically.
172 */
173#define MAX_VIDEO_MODES 128
174#ifndef VBOX_WITH_MULTIMONITOR_FIX
175static VIDEO_MODE_INFORMATION VideoModes[MAX_VIDEO_MODES + 2] = { 0 };
176#else
177/*
178 * Additional space is reserved for custom video modes for 64 guest monitors.
179 * The custom video mode index is alternating and 2 indexes are reserved for the last custom mode.
180 */
181static VIDEO_MODE_INFORMATION VideoModes[MAX_VIDEO_MODES + 64 + 2] = { 0 };
182/* On the driver startup this is initialized from registry (replaces gCustom*). */
183static VIDEO_MODE_INFORMATION CustomVideoModes[64] = { 0 };
184#endif /* VBOX_WITH_MULTIMONITOR_FIX */
185/* number of available video modes, set by VBoxBuildModesTable */
186static uint32_t gNumVideoModes = 0;
187
188#ifdef VBOX_WITH_MULTIMONITOR_FIX
189static void initVideoModeInformation(VIDEO_MODE_INFORMATION *pVideoMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index, ULONG yoffset)
190{
191 /*
192 * Build mode entry.
193 */
194 memset(pVideoMode, 0, sizeof(VIDEO_MODE_INFORMATION));
195
196 pVideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
197 pVideoMode->ModeIndex = index;
198 pVideoMode->VisScreenWidth = xres;
199 pVideoMode->VisScreenHeight = yres - yoffset;
200 pVideoMode->ScreenStride = xres * ((bpp + 7) / 8);
201 pVideoMode->NumberOfPlanes = 1;
202 pVideoMode->BitsPerPlane = bpp;
203 pVideoMode->Frequency = 60;
204 pVideoMode->XMillimeter = 320;
205 pVideoMode->YMillimeter = 240;
206 switch (bpp)
207 {
208#ifdef VBOX_WITH_8BPP_MODES
209 case 8:
210 pVideoMode->NumberRedBits = 6;
211 pVideoMode->NumberGreenBits = 6;
212 pVideoMode->NumberBlueBits = 6;
213 pVideoMode->RedMask = 0;
214 pVideoMode->GreenMask = 0;
215 pVideoMode->BlueMask = 0;
216 break;
217#endif
218 case 16:
219 pVideoMode->NumberRedBits = 5;
220 pVideoMode->NumberGreenBits = 6;
221 pVideoMode->NumberBlueBits = 5;
222 pVideoMode->RedMask = 0xF800;
223 pVideoMode->GreenMask = 0x7E0;
224 pVideoMode->BlueMask = 0x1F;
225 break;
226 case 24:
227 pVideoMode->NumberRedBits = 8;
228 pVideoMode->NumberGreenBits = 8;
229 pVideoMode->NumberBlueBits = 8;
230 pVideoMode->RedMask = 0xFF0000;
231 pVideoMode->GreenMask = 0xFF00;
232 pVideoMode->BlueMask = 0xFF;
233 break;
234 case 32:
235 pVideoMode->NumberRedBits = 8;
236 pVideoMode->NumberGreenBits = 8;
237 pVideoMode->NumberBlueBits = 8;
238 pVideoMode->RedMask = 0xFF0000;
239 pVideoMode->GreenMask = 0xFF00;
240 pVideoMode->BlueMask = 0xFF;
241 break;
242 }
243 pVideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
244#ifdef VBOX_WITH_8BPP_MODES
245 if (bpp == 8)
246 pVideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
247#endif
248 pVideoMode->VideoMemoryBitmapWidth = xres;
249 pVideoMode->VideoMemoryBitmapHeight = yres - yoffset;
250 pVideoMode->DriverSpecificAttributeFlags = 0;
251}
252#endif /* VBOX_WITH_MULTIMONITOR_FIX */
253
254#ifdef VBOXWDDM
255/* preferred mode index */
256static uint32_t gPreferredVideoMode = 0;
257
258static D3DKMDT_2DREGION g_VBoxWddmVideoResolutions[RT_ELEMENTS(VideoModes)];
259static uint32_t g_VBoxWddmNumResolutions;
260
261DECLINLINE(int) vboxWddmRectComparator(const D3DKMDT_2DREGION *pReg1, const D3DKMDT_2DREGION *pReg2)
262{
263 int tmp = pReg1->cx - pReg2->cx;
264 if(tmp)
265 return tmp;
266 tmp = pReg1->cy - pReg2->cy;
267 return tmp;
268}
269
270/* builds a g_VBoxWddmVideoResolutions given VideoModes info */
271VOID vboxWddmBuildResolutionTable()
272{
273 g_VBoxWddmNumResolutions = 0;
274
275 /* we don't care about the efficiency at this time */
276 for (uint32_t i = 0; i < gNumVideoModes; ++i)
277 {
278 VIDEO_MODE_INFORMATION *pMode = &VideoModes[i];
279 bool bFound = false;
280 for (uint32_t j = 0; j < g_VBoxWddmNumResolutions; ++j)
281 {
282 if (g_VBoxWddmVideoResolutions[j].cx == pMode->VisScreenWidth
283 && g_VBoxWddmVideoResolutions[j].cy == pMode->VisScreenHeight)
284 {
285 bFound = true;
286 break;
287 }
288 }
289
290 if (!bFound)
291 {
292 Assert(g_VBoxWddmNumResolutions < RT_ELEMENTS(g_VBoxWddmVideoResolutions));
293 g_VBoxWddmVideoResolutions[g_VBoxWddmNumResolutions].cx = pMode->VisScreenWidth;
294 g_VBoxWddmVideoResolutions[g_VBoxWddmNumResolutions].cy = pMode->VisScreenHeight;
295 ++g_VBoxWddmNumResolutions;
296 }
297 }
298}
299#endif
300
301static uint32_t g_xresNoVRAM = 0, g_yresNoVRAM = 0, g_bppNoVRAM = 0;
302
303/**
304 * Helper function to dynamically build our table of standard video
305 * modes. We take the amount of VRAM and create modes with standard
306 * geometries until we've either reached the maximum number of modes
307 * or the available VRAM does not allow for additional modes.
308 */
309VOID VBoxBuildModesTable(PDEVICE_EXTENSION DeviceExtension)
310{
311 /* we need this static counter to always have a new mode index for our */
312 /* custom video mode, otherwise Windows thinks there is no mode switch */
313 static int gInvocationCounter = 0;
314
315 VBOXCMNREG Reg;
316 VBoxVideoCmnRegInit(DeviceExtension, &Reg);
317
318 /* the resolution matrix */
319 struct
320 {
321 uint16_t xRes;
322 uint16_t yRes;
323 } resolutionMatrix[] =
324 {
325 /* standard modes */
326 { 640, 480 },
327 { 800, 600 },
328 { 1024, 768 },
329 { 1152, 864 },
330 { 1280, 960 },
331 { 1280, 1024 },
332 { 1400, 1050 },
333 { 1600, 1200 },
334 { 1920, 1440 },
335 /* multi screen modes with 1280x1024 */
336 { 2560, 1024 },
337 { 3840, 1024 },
338 { 5120, 1024 },
339 /* multi screen modes with 1600x1200 */
340 { 3200, 1200 },
341 { 4800, 1200 },
342 { 6400, 1200 },
343 };
344 size_t matrixSize = sizeof(resolutionMatrix) / sizeof(resolutionMatrix[0]);
345
346 /* there are 4 color depths: 8, 16, 24 and 32bpp and we reserve 50% of the modes for other sources */
347 size_t maxModesPerColorDepth = MAX_VIDEO_MODES / 2 / 4;
348
349 /* size of the VRAM in bytes */
350
351#ifndef VBOXWDDM
352 ULONG vramSize = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
353#else
354 ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(DeviceExtension);
355#ifndef VBOXWDDM_RENDER_FROM_SHADOW
356 /* at least two surfaces will be needed: primary & shadow */
357 vramSize /= 2;
358#endif
359
360 gPreferredVideoMode = 0;
361#endif
362
363 gNumVideoModes = 0;
364
365 size_t numModesCurrentColorDepth;
366 size_t matrixIndex;
367 VP_STATUS status = 0;
368
369 /* Always add 800x600 video modes. Windows XP+ needs at least 800x600 resolution
370 * and fallbacks to 800x600x4bpp VGA mode if the driver did not report suitable modes.
371 * This resolution could be rejected by a low resolution host (netbooks, etc).
372 */
373 int cBytesPerPixel;
374 for (cBytesPerPixel = 1; cBytesPerPixel <= 4; cBytesPerPixel++)
375 {
376 int cBitsPerPixel = cBytesPerPixel * 8; /* 8, 16, 24, 32 */
377
378#ifndef VBOX_WITH_8BPP_MODES
379 if (cBitsPerPixel == 8)
380 {
381 continue;
382 }
383#endif /* !VBOX_WITH_8BPP_MODES */
384
385 /* does the mode fit into the VRAM? */
386 if (800 * 600 * cBytesPerPixel > (LONG)vramSize)
387 {
388 continue;
389 }
390
391 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
392 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
393 VideoModes[gNumVideoModes].VisScreenWidth = 800;
394 VideoModes[gNumVideoModes].VisScreenHeight = 600;
395 VideoModes[gNumVideoModes].ScreenStride = 800 * cBytesPerPixel;
396 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
397 VideoModes[gNumVideoModes].BitsPerPlane = cBitsPerPixel;
398 VideoModes[gNumVideoModes].Frequency = 60;
399 VideoModes[gNumVideoModes].XMillimeter = 320;
400 VideoModes[gNumVideoModes].YMillimeter = 240;
401 switch (cBytesPerPixel)
402 {
403 case 1:
404 {
405 VideoModes[gNumVideoModes].NumberRedBits = 6;
406 VideoModes[gNumVideoModes].NumberGreenBits = 6;
407 VideoModes[gNumVideoModes].NumberBlueBits = 6;
408 VideoModes[gNumVideoModes].RedMask = 0;
409 VideoModes[gNumVideoModes].GreenMask = 0;
410 VideoModes[gNumVideoModes].BlueMask = 0;
411 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
412 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
413 } break;
414 case 2:
415 {
416 VideoModes[gNumVideoModes].NumberRedBits = 5;
417 VideoModes[gNumVideoModes].NumberGreenBits = 6;
418 VideoModes[gNumVideoModes].NumberBlueBits = 5;
419 VideoModes[gNumVideoModes].RedMask = 0xF800;
420 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
421 VideoModes[gNumVideoModes].BlueMask = 0x1F;
422 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
423 } break;
424 case 3:
425 {
426 VideoModes[gNumVideoModes].NumberRedBits = 8;
427 VideoModes[gNumVideoModes].NumberGreenBits = 8;
428 VideoModes[gNumVideoModes].NumberBlueBits = 8;
429 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
430 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
431 VideoModes[gNumVideoModes].BlueMask = 0xFF;
432 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
433 } break;
434 default:
435 case 4:
436 {
437 VideoModes[gNumVideoModes].NumberRedBits = 8;
438 VideoModes[gNumVideoModes].NumberGreenBits = 8;
439 VideoModes[gNumVideoModes].NumberBlueBits = 8;
440 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
441 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
442 VideoModes[gNumVideoModes].BlueMask = 0xFF;
443 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
444#ifdef VBOXWDDM
445 gPreferredVideoMode = gNumVideoModes;
446#endif
447 } break;
448 }
449 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = 800;
450 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = 600;
451 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
452
453 /* a new mode has been filled in */
454 ++gNumVideoModes;
455 }
456
457 /*
458 * Query the y-offset from the host
459 */
460 ULONG yOffset = vboxGetHeightReduction();
461
462#ifdef VBOX_WITH_8BPP_MODES
463 /*
464 * 8 bit video modes
465 */
466 numModesCurrentColorDepth = 0;
467 matrixIndex = 0;
468 while (numModesCurrentColorDepth < maxModesPerColorDepth)
469 {
470 /* are there any modes left in the matrix? */
471 if (matrixIndex >= matrixSize)
472 break;
473
474 /* does the mode fit into the VRAM? */
475 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 1 > (LONG)vramSize)
476 {
477 ++matrixIndex;
478 continue;
479 }
480
481 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
482 {
483 /* This mode was already added. */
484 ++matrixIndex;
485 continue;
486 }
487
488 /* does the host like that mode? */
489#ifndef VBOXWDDM
490 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 8))
491#else
492 if (!vboxLikesVideoMode(0 /* @todo: */, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 8))
493#endif
494 {
495 ++matrixIndex;
496 continue;
497 }
498
499 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
500 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
501 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
502 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
503 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 1;
504 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
505 VideoModes[gNumVideoModes].BitsPerPlane = 8;
506 VideoModes[gNumVideoModes].Frequency = 60;
507 VideoModes[gNumVideoModes].XMillimeter = 320;
508 VideoModes[gNumVideoModes].YMillimeter = 240;
509 VideoModes[gNumVideoModes].NumberRedBits = 6;
510 VideoModes[gNumVideoModes].NumberGreenBits = 6;
511 VideoModes[gNumVideoModes].NumberBlueBits = 6;
512 VideoModes[gNumVideoModes].RedMask = 0;
513 VideoModes[gNumVideoModes].GreenMask = 0;
514 VideoModes[gNumVideoModes].BlueMask = 0;
515 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
516 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
517 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
518 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
519 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
520
521 /* a new mode has been filled in */
522 ++gNumVideoModes;
523 ++numModesCurrentColorDepth;
524 /* advance to the next mode matrix entry */
525 ++matrixIndex;
526 }
527#endif /* VBOX_WITH_8BPP_MODES */
528
529 /*
530 * 16 bit video modes
531 */
532 numModesCurrentColorDepth = 0;
533 matrixIndex = 0;
534 while (numModesCurrentColorDepth < maxModesPerColorDepth)
535 {
536 /* are there any modes left in the matrix? */
537 if (matrixIndex >= matrixSize)
538 break;
539
540 /* does the mode fit into the VRAM? */
541 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 2 > (LONG)vramSize)
542 {
543 ++matrixIndex;
544 continue;
545 }
546
547 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
548 {
549 /* This mode was already added. */
550 ++matrixIndex;
551 continue;
552 }
553
554 /* does the host like that mode? */
555#ifndef VBOXWDDM
556 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 16))
557#else
558 if (!vboxLikesVideoMode(0 /* @todo: */, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 16))
559#endif
560
561 {
562 ++matrixIndex;
563 continue;
564 }
565
566 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
567 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
568 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
569 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
570 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 2;
571 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
572 VideoModes[gNumVideoModes].BitsPerPlane = 16;
573 VideoModes[gNumVideoModes].Frequency = 60;
574 VideoModes[gNumVideoModes].XMillimeter = 320;
575 VideoModes[gNumVideoModes].YMillimeter = 240;
576 VideoModes[gNumVideoModes].NumberRedBits = 5;
577 VideoModes[gNumVideoModes].NumberGreenBits = 6;
578 VideoModes[gNumVideoModes].NumberBlueBits = 5;
579 VideoModes[gNumVideoModes].RedMask = 0xF800;
580 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
581 VideoModes[gNumVideoModes].BlueMask = 0x1F;
582 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
583 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
584 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
585 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
586
587 /* a new mode has been filled in */
588 ++gNumVideoModes;
589 ++numModesCurrentColorDepth;
590 /* advance to the next mode matrix entry */
591 ++matrixIndex;
592 }
593
594 /*
595 * 24 bit video modes
596 */
597 numModesCurrentColorDepth = 0;
598 matrixIndex = 0;
599 while (numModesCurrentColorDepth < maxModesPerColorDepth)
600 {
601 /* are there any modes left in the matrix? */
602 if (matrixIndex >= matrixSize)
603 break;
604
605 /* does the mode fit into the VRAM? */
606 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 3 > (LONG)vramSize)
607 {
608 ++matrixIndex;
609 continue;
610 }
611
612 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
613 {
614 /* This mode was already added. */
615 ++matrixIndex;
616 continue;
617 }
618
619 /* does the host like that mode? */
620#ifndef VBOXWDDM
621 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 24))
622#else
623 if (!vboxLikesVideoMode(0, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 24))
624#endif
625 {
626 ++matrixIndex;
627 continue;
628 }
629
630 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
631 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
632 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
633 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
634 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 3;
635 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
636 VideoModes[gNumVideoModes].BitsPerPlane = 24;
637 VideoModes[gNumVideoModes].Frequency = 60;
638 VideoModes[gNumVideoModes].XMillimeter = 320;
639 VideoModes[gNumVideoModes].YMillimeter = 240;
640 VideoModes[gNumVideoModes].NumberRedBits = 8;
641 VideoModes[gNumVideoModes].NumberGreenBits = 8;
642 VideoModes[gNumVideoModes].NumberBlueBits = 8;
643 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
644 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
645 VideoModes[gNumVideoModes].BlueMask = 0xFF;
646 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
647 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
648 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
649 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
650
651 /* a new mode has been filled in */
652 ++gNumVideoModes;
653 ++numModesCurrentColorDepth;
654 /* advance to the next mode matrix entry */
655 ++matrixIndex;
656 }
657
658 /*
659 * 32 bit video modes
660 */
661 numModesCurrentColorDepth = 0;
662 matrixIndex = 0;
663 while (numModesCurrentColorDepth < maxModesPerColorDepth)
664 {
665 /* are there any modes left in the matrix? */
666 if (matrixIndex >= matrixSize)
667 break;
668
669 /* does the mode fit into the VRAM? */
670 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 4 > (LONG)vramSize)
671 {
672 ++matrixIndex;
673 continue;
674 }
675
676 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
677 {
678 /* This mode was already added. */
679 ++matrixIndex;
680 continue;
681 }
682
683 /* does the host like that mode? */
684#ifndef VBOXWDDM
685 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 32))
686#else
687 if (!vboxLikesVideoMode(0, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 32))
688#endif
689 {
690 ++matrixIndex;
691 continue;
692 }
693
694 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
695 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
696 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
697 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
698 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 4;
699 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
700 VideoModes[gNumVideoModes].BitsPerPlane = 32;
701 VideoModes[gNumVideoModes].Frequency = 60;
702 VideoModes[gNumVideoModes].XMillimeter = 320;
703 VideoModes[gNumVideoModes].YMillimeter = 240;
704 VideoModes[gNumVideoModes].NumberRedBits = 8;
705 VideoModes[gNumVideoModes].NumberGreenBits = 8;
706 VideoModes[gNumVideoModes].NumberBlueBits = 8;
707 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
708 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
709 VideoModes[gNumVideoModes].BlueMask = 0xFF;
710 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
711 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
712 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
713 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
714
715 /* a new mode has been filled in */
716 ++gNumVideoModes;
717 ++numModesCurrentColorDepth;
718 /* advance to the next mode matrix entry */
719 ++matrixIndex;
720 }
721
722 /*
723 * Next, check the registry for additional modes
724 */
725 int curKeyNo = 0;
726#ifdef VBOXWDDM
727 int fPreferredSet = 0;
728#endif
729 do
730 {
731 /* check if there is space in the mode list */
732 if (gNumVideoModes >= MAX_VIDEO_MODES)
733 break;
734
735 wchar_t keyname[24];
736 uint32_t xres, yres, bpp = 0;
737 swprintf(keyname, L"CustomMode%dWidth", curKeyNo);
738 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &xres);
739 /* upon the first error, we give up */
740 if (status != NO_ERROR)
741 break;
742 swprintf(keyname, L"CustomMode%dHeight", curKeyNo);
743 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &yres);
744 /* upon the first error, we give up */
745 if (status != NO_ERROR)
746 break;
747 swprintf(keyname, L"CustomMode%dBPP", curKeyNo);
748 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &bpp);
749 /* upon the first error, we give up */
750 if (status != NO_ERROR)
751 break;
752
753 dprintf(("VBoxVideo: custom mode %u returned: xres = %u, yres = %u, bpp = %u\n",
754 curKeyNo, xres, yres, bpp));
755
756 /* first test: do the values make sense? */
757 if ( (xres > (1 << 16))
758 || (yres > (1 << 16))
759 || ( (bpp != 16)
760 && (bpp != 24)
761 && (bpp != 32)))
762 break;
763
764 /* round down width to be a multiple of 8 */
765 xres &= 0xFFF8;
766
767 /* second test: does it fit within our VRAM? */
768 if (xres * yres * (bpp / 8) > vramSize)
769 break;
770
771 /* third test: does the host like the video mode? */
772#ifndef VBOXWDDM
773 if (!vboxLikesVideoMode(DeviceExtension->iDevice, xres, yres, bpp))
774#else
775 if (!vboxLikesVideoMode(0, xres, yres, bpp))
776#endif
777 break;
778
779 dprintf(("VBoxVideo: adding mode from registry: xres = %d, yres = %d, bpp = %d\n", xres, yres, bpp));
780
781#ifdef VBOXWDDM
782 if (!fPreferredSet)
783 {
784 gPreferredVideoMode = gNumVideoModes;
785 fPreferredSet = 1;
786 }
787#endif
788 /*
789 * Build mode entry.
790 * Note that we have to apply the y offset for the custom mode.
791 */
792 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
793 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
794 VideoModes[gNumVideoModes].VisScreenWidth = xres;
795 VideoModes[gNumVideoModes].VisScreenHeight = yres - yOffset;
796 VideoModes[gNumVideoModes].ScreenStride = xres * (bpp / 8);
797 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
798 VideoModes[gNumVideoModes].BitsPerPlane = bpp;
799 VideoModes[gNumVideoModes].Frequency = 60;
800 VideoModes[gNumVideoModes].XMillimeter = 320;
801 VideoModes[gNumVideoModes].YMillimeter = 240;
802 switch (bpp)
803 {
804 case 16:
805 VideoModes[gNumVideoModes].NumberRedBits = 5;
806 VideoModes[gNumVideoModes].NumberGreenBits = 6;
807 VideoModes[gNumVideoModes].NumberBlueBits = 5;
808 VideoModes[gNumVideoModes].RedMask = 0xF800;
809 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
810 VideoModes[gNumVideoModes].BlueMask = 0x1F;
811 break;
812 case 24:
813 VideoModes[gNumVideoModes].NumberRedBits = 8;
814 VideoModes[gNumVideoModes].NumberGreenBits = 8;
815 VideoModes[gNumVideoModes].NumberBlueBits = 8;
816 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
817 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
818 VideoModes[gNumVideoModes].BlueMask = 0xFF;
819 break;
820 case 32:
821 VideoModes[gNumVideoModes].NumberRedBits = 8;
822 VideoModes[gNumVideoModes].NumberGreenBits = 8;
823 VideoModes[gNumVideoModes].NumberBlueBits = 8;
824 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
825 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
826 VideoModes[gNumVideoModes].BlueMask = 0xFF;
827#ifdef VBOXWDDM
828 /* 32-bit mode is more preferable, select it if not yet */
829 if (fPreferredSet < 2)
830 {
831 gPreferredVideoMode = gNumVideoModes;
832 fPreferredSet = 2;
833 }
834#endif
835 break;
836 }
837 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
838 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = xres;
839 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = yres - yOffset;
840 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
841 ++gNumVideoModes;
842
843 /* next run */
844 curKeyNo++;
845 /* only support 128 modes for now */
846 if (curKeyNo >= 128)
847 break;
848
849 } while(1);
850
851 /*
852 * Now we ask the host for a display change request. If there's one,
853 * this will be appended as a special mode so that it can be used by
854 * the Additions service process. The mode table is guaranteed to have
855 * two spare entries for this mode (alternating index thus 2).
856 *
857 * ... or ...
858 *
859 * Also we check if we got an user-stored custom resolution in the adapter
860 * registry key add it to the modes table.
861 */
862
863#ifdef VBOX_WITH_MULTIMONITOR_FIX
864 /* Add custom resolutions for each display and then for the display change request, if exists.
865 */
866 BOOLEAN fDisplayChangeRequest = FALSE;
867
868 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
869 if ( vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
870 && (xres || yres || bpp))
871 {
872 /* There is a pending display change request. */
873 fDisplayChangeRequest = TRUE;
874 }
875 if (display > RT_ELEMENTS(CustomVideoModes))
876 {
877 display = RT_ELEMENTS(CustomVideoModes) - 1;
878 }
879
880 dprintf(("display = %d, DeviceExtension->iDevice = %d\n", display, DeviceExtension->iDevice));
881 if (display != DeviceExtension->iDevice)
882 {
883 /* No need to go through the custom mode logic. And no need to clear the custom mode
884 * entry in the next 'for' loop.
885 */
886 fDisplayChangeRequest = FALSE;
887 }
888
889 dprintf(("VBoxVideo: fDisplayChangeRequest = %d\n", fDisplayChangeRequest));
890
891 /*
892 * Reinsert custom video modes for all displays.
893 */
894 int iCustomMode;
895 for (iCustomMode = 0; iCustomMode < DeviceExtension->pPrimary->u.primary.cDisplays; iCustomMode++)
896 {
897 if (fDisplayChangeRequest && iCustomMode == display)
898 {
899 /* Do not keep info for this display, which received a video mode hint, to make sure that
900 * the new mode will be taken from the alternating index entries actually.
901 */
902 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
903 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
904 }
905 else
906 {
907 VideoModes[gNumVideoModes] = CustomVideoModes[iCustomMode];
908 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
909 }
910#ifdef LOG_ENABLED
911 dprintf(("Custom mode for %2d: %4d x %4d @ %2d\n",
912 iCustomMode, CustomVideoModes[iCustomMode].VisScreenWidth,
913 CustomVideoModes[iCustomMode].VisScreenHeight, CustomVideoModes[iCustomMode].BitsPerPlane));
914#endif
915 gNumVideoModes++;
916 }
917
918 if (display != DeviceExtension->iDevice)
919 {
920 /* The display change is for another monitor. Just add 2 standard modes to the table
921 * to make enough entries. This is not necessary if it is a first mode set (CurrentMode == 0),
922 * because these 2 entries will be added by "if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)"
923 * code branch.
924 */
925 if (DeviceExtension->CurrentMode != 0)
926 {
927 dprintf(("Filling custom mode entries.\n"));
928 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
929 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
930 gNumVideoModes++;
931 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
932 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
933 gNumVideoModes++;
934 }
935 }
936#endif /* VBOX_WITH_MULTIMONITOR_FIX */
937
938#ifndef VBOX_WITH_MULTIMONITOR_FIX
939 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
940 if ( ( vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
941 && (xres || yres || bpp))
942 || (gCustomXRes || gCustomYRes || gCustomBPP))
943#else
944 if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)
945#endif /* VBOX_WITH_MULTIMONITOR_FIX */
946 {
947#ifndef VBOXWDDM
948 dprintf(("VBoxVideo: adding custom video mode as #%d, current mode: %d \n", gNumVideoModes + 1, DeviceExtension->CurrentMode));
949 /* handle the startup case */
950 if (DeviceExtension->CurrentMode == 0)
951#else
952 if (!DeviceExtension->u.primary.cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
953#endif
954 {
955 /* Use the stored custom resolution values only if nothing was read from host.
956 * The custom mode might be not valid anymore and would block any hints from host.
957 */
958#ifndef VBOX_WITH_MULTIMONITOR_FIX
959 if (!xres)
960 xres = gCustomXRes;
961 if (!yres)
962 yres = gCustomYRes;
963 if (!bpp)
964 bpp = gCustomBPP;
965 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d\n", xres, yres, bpp));
966#else
967 if (!xres)
968 xres = CustomVideoModes[DeviceExtension->iDevice].VisScreenWidth;
969 if (!yres)
970 yres = CustomVideoModes[DeviceExtension->iDevice].VisScreenHeight;
971 if (!bpp)
972 bpp = CustomVideoModes[DeviceExtension->iDevice].BitsPerPlane;
973 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d for %d\n", xres, yres, bpp, DeviceExtension->iDevice));
974#endif /* VBOX_WITH_MULTIMONITOR_FIX */
975 }
976 /* round down to multiple of 8 */
977 if ((xres & 0xfff8) != xres)
978 dprintf(("VBoxVideo: rounding down xres from %d to %d\n", xres, xres & 0xfff8));
979 xres &= 0xfff8;
980 /* take the current values for the fields that are not set */
981#ifndef VBOXWDDM
982 if (DeviceExtension->CurrentMode != 0)
983 {
984 if (!xres)
985 xres = DeviceExtension->CurrentModeWidth;
986 if (!yres)
987 yres = DeviceExtension->CurrentModeHeight;
988 if (!bpp)
989 bpp = DeviceExtension->CurrentModeBPP;
990 }
991#else
992 if (DeviceExtension->u.primary.cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
993 {
994 if (!xres)
995 xres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.width;
996 if (!yres)
997 yres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.height;
998 if (!bpp)
999 bpp = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.bpp;
1000 }
1001#endif
1002
1003 /* Use a default value. */
1004 if (!bpp)
1005 bpp = 32;
1006
1007 /* does the host like that mode? */
1008#ifndef VBOXWDDM
1009 if (vboxLikesVideoMode(DeviceExtension->iDevice, xres, yres, bpp))
1010#else
1011 if (vboxLikesVideoMode(0, xres, yres, bpp))
1012#endif
1013 {
1014 /* we must have a valid video mode by now and it must fit within the VRAM */
1015 if ( ( xres
1016 && yres
1017 && ( (bpp == 16)
1018#ifdef VBOX_WITH_8BPP_MODES
1019 || (bpp == 8)
1020#endif
1021 || (bpp == 24)
1022 || (bpp == 32)))
1023 && (xres * yres * (bpp / 8) < vramSize))
1024
1025 {
1026 /* we need an alternating index */
1027#ifdef VBOX_WITH_MULTIMONITOR_FIX
1028 /* Only alternate index if the new custom mode differs from the last one
1029 * (only resolution and bpp changes are important, a display change does not matter).
1030 * Always add 2 last entries to the mode array, so number of video modes
1031 * do not change.
1032 */
1033 BOOLEAN fNewInvocation = FALSE;
1034 static uint32_t sPrev_xres = 0;
1035 static uint32_t sPrev_yres = 0;
1036 static uint32_t sPrev_bpp = 0;
1037 if ( sPrev_xres != xres
1038 || sPrev_yres != yres
1039 || sPrev_bpp != bpp)
1040 {
1041 sPrev_xres = xres;
1042 sPrev_yres = yres;
1043 sPrev_bpp = bpp;
1044 fNewInvocation = TRUE;
1045 }
1046 BOOLEAN fAlternatedIndex = FALSE;
1047#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1048#ifndef VBOXWDDM
1049 if (DeviceExtension->CurrentMode != 0)
1050#else
1051 if (DeviceExtension->u.primary.cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
1052#endif
1053#ifndef VBOX_WITH_MULTIMONITOR_FIX
1054 {
1055 if (gInvocationCounter % 2)
1056 gNumVideoModes++;
1057 gInvocationCounter++;
1058 }
1059#else
1060 {
1061 if (fNewInvocation)
1062 gInvocationCounter++;
1063 if (gInvocationCounter % 2)
1064 {
1065 fAlternatedIndex = TRUE;
1066
1067 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
1068 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1069 gNumVideoModes++;
1070 }
1071 }
1072 else
1073 {
1074 fNewInvocation = FALSE;
1075 }
1076#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1077
1078 dprintf(("VBoxVideo: setting special mode to xres = %d, yres = %d, bpp = %d, display = %d\n", xres, yres, bpp, display));
1079#ifdef VBOX_WITH_MULTIMONITOR_FIX
1080 dprintf(("VBoxVideo: fNewInvocation = %d, fAlternatedIndex = %d\n", fNewInvocation, fAlternatedIndex));
1081#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1082#ifdef VBOXWDDM
1083 /* assign host-supplied as the most preferable */
1084 gPreferredVideoMode = gNumVideoModes;
1085#endif
1086 /*
1087 * Build mode entry.
1088 * Note that we do not apply the y offset for the custom mode. It is
1089 * only used for the predefined modes that the user can configure in
1090 * the display properties dialog.
1091 */
1092 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1093 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1094 VideoModes[gNumVideoModes].VisScreenWidth = xres;
1095 VideoModes[gNumVideoModes].VisScreenHeight = yres;
1096 VideoModes[gNumVideoModes].ScreenStride = xres * (bpp / 8);
1097 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1098 VideoModes[gNumVideoModes].BitsPerPlane = bpp;
1099 VideoModes[gNumVideoModes].Frequency = 60;
1100 VideoModes[gNumVideoModes].XMillimeter = 320;
1101 VideoModes[gNumVideoModes].YMillimeter = 240;
1102 switch (bpp)
1103 {
1104#ifdef VBOX_WITH_8BPP_MODES
1105 case 8:
1106 VideoModes[gNumVideoModes].NumberRedBits = 6;
1107 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1108 VideoModes[gNumVideoModes].NumberBlueBits = 6;
1109 VideoModes[gNumVideoModes].RedMask = 0;
1110 VideoModes[gNumVideoModes].GreenMask = 0;
1111 VideoModes[gNumVideoModes].BlueMask = 0;
1112 break;
1113#endif
1114 case 16:
1115 VideoModes[gNumVideoModes].NumberRedBits = 5;
1116 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1117 VideoModes[gNumVideoModes].NumberBlueBits = 5;
1118 VideoModes[gNumVideoModes].RedMask = 0xF800;
1119 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
1120 VideoModes[gNumVideoModes].BlueMask = 0x1F;
1121 break;
1122 case 24:
1123 VideoModes[gNumVideoModes].NumberRedBits = 8;
1124 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1125 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1126 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1127 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1128 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1129 break;
1130 case 32:
1131 VideoModes[gNumVideoModes].NumberRedBits = 8;
1132 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1133 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1134 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1135 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1136 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1137 break;
1138 }
1139 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1140#ifdef VBOX_WITH_8BPP_MODES
1141 if (bpp == 8)
1142 VideoModes[gNumVideoModes].AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
1143#endif
1144 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = xres;
1145 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = yres;
1146 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
1147#ifdef VBOX_WITH_MULTIMONITOR_FIX
1148 /* Save the mode in the list of custom modes for this display. */
1149 CustomVideoModes[DeviceExtension->iDevice] = VideoModes[gNumVideoModes];
1150#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1151 ++gNumVideoModes;
1152
1153 /* for the startup case, we need this mode twice due to the alternating mode number */
1154#ifndef VBOXWDDM
1155 if (DeviceExtension->CurrentMode == 0)
1156#else
1157 if (!DeviceExtension->u.primary.cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
1158#endif
1159 {
1160 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
1161 memcpy(&VideoModes[gNumVideoModes], &VideoModes[gNumVideoModes - 1], sizeof(VIDEO_MODE_INFORMATION));
1162 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1163 gNumVideoModes++;
1164 }
1165#ifdef VBOX_WITH_MULTIMONITOR_FIX
1166 else if (!fAlternatedIndex)
1167 {
1168 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
1169 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
1170 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1171 gNumVideoModes++;
1172 }
1173#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1174
1175#ifndef VBOX_WITH_MULTIMONITOR_FIX
1176 /* store this video mode as the last custom video mode */
1177 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
1178 if (status != NO_ERROR)
1179 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
1180 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
1181 if (status != NO_ERROR)
1182 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
1183 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
1184 if (status != NO_ERROR)
1185 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
1186#else
1187 /* Save the custom mode for this display. */
1188 if (DeviceExtension->iDevice == 0)
1189 {
1190 /* Name without a suffix */
1191 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
1192 if (status != NO_ERROR)
1193 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
1194 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
1195 if (status != NO_ERROR)
1196 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
1197 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
1198 if (status != NO_ERROR)
1199 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
1200 }
1201 else
1202 {
1203 wchar_t keyname[32];
1204 swprintf(keyname, L"CustomXRes%d", DeviceExtension->iDevice);
1205 status = VBoxVideoCmnRegSetDword(Reg, keyname, xres);
1206 if (status != NO_ERROR)
1207 dprintf(("VBoxVideo: error %d writing CustomXRes%d\n", status, DeviceExtension->iDevice));
1208 swprintf(keyname, L"CustomYRes%d", DeviceExtension->iDevice);
1209 status = VBoxVideoCmnRegSetDword(Reg, keyname, yres);
1210 if (status != NO_ERROR)
1211 dprintf(("VBoxVideo: error %d writing CustomYRes%d\n", status, DeviceExtension->iDevice));
1212 swprintf(keyname, L"CustomBPP%d", DeviceExtension->iDevice);
1213 status = VBoxVideoCmnRegSetDword(Reg, keyname, bpp);
1214 if (status != NO_ERROR)
1215 dprintf(("VBoxVideo: error %d writing CustomBPP%d\n", status, DeviceExtension->iDevice));
1216 }
1217#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1218 }
1219 else
1220 {
1221 dprintf(("VBoxVideo: invalid parameters for special mode: (xres = %d, yres = %d, bpp = %d, vramSize = %d)\n",
1222 xres, yres, bpp, vramSize));
1223 if (xres * yres * (bpp / 8) >= vramSize
1224 && (xres != g_xresNoVRAM || yres != g_yresNoVRAM || bpp != g_bppNoVRAM))
1225 {
1226 LogRel(("VBoxVideo: not enough VRAM for video mode %dx%dx%dbpp. Available: %d bytes. Required: more than %d bytes.\n",
1227 xres, yres, bpp, vramSize, xres * yres * (bpp / 8)));
1228 g_xresNoVRAM = xres;
1229 g_yresNoVRAM = yres;
1230 g_bppNoVRAM = bpp;
1231 }
1232 }
1233 }
1234 else
1235 dprintf(("VBoxVideo: host does not like special mode: (xres = %d, yres = %d, bpp = %d)\n",
1236 xres, yres, bpp));
1237 }
1238#if defined(LOG_ENABLED)
1239 {
1240 int i;
1241#ifndef VBOXWDDM
1242 dprintf(("VBoxVideo: VideoModes (CurrentMode = %d, last #%d)\n", DeviceExtension->CurrentMode, gNumVideoModes));
1243#endif
1244 for (i = 0; i < RT_ELEMENTS(VideoModes); i++)
1245 {
1246 if ( VideoModes[i].VisScreenWidth
1247 || VideoModes[i].VisScreenHeight
1248 || VideoModes[i].BitsPerPlane)
1249 {
1250 dprintf((" %2d: #%d %4d x %4d @ %2d\n",
1251 i, VideoModes[i].ModeIndex, VideoModes[i].VisScreenWidth,
1252 VideoModes[i].VisScreenHeight, VideoModes[i].BitsPerPlane));
1253 }
1254 }
1255 }
1256#endif
1257
1258#ifdef VBOXWDDM
1259 vboxWddmBuildResolutionTable();
1260#endif
1261
1262 VBoxVideoCmnRegFini(Reg);
1263}
1264
1265#ifdef VBOXWDDM
1266static bool g_bModesTableInitialized = false;
1267/**
1268 * Helper function to dynamically build our table of standard video
1269 * modes. We take the amount of VRAM and create modes with standard
1270 * geometries until we've either reached the maximum number of modes
1271 * or the available VRAM does not allow for additional modes.
1272 */
1273VOID VBoxWddmGetModesTable(PDEVICE_EXTENSION DeviceExtension, bool bRebuildTable,
1274 VIDEO_MODE_INFORMATION ** ppModes, uint32_t * pcModes, int32_t * pPreferrableMode,
1275 D3DKMDT_2DREGION **ppResolutions, uint32_t * pcResolutions)
1276{
1277 if(bRebuildTable || !g_bModesTableInitialized)
1278 {
1279 VBoxBuildModesTable(DeviceExtension);
1280 g_bModesTableInitialized = true;
1281 }
1282
1283 *ppModes = VideoModes;
1284 *pcModes = gNumVideoModes;
1285 *pPreferrableMode = (int32_t)gPreferredVideoMode;
1286 *ppResolutions = g_VBoxWddmVideoResolutions;
1287 *pcResolutions = g_VBoxWddmNumResolutions;
1288}
1289
1290VOID VBoxWddmInvalidateModesTable(PDEVICE_EXTENSION DeviceExtension)
1291{
1292 g_bModesTableInitialized = false;
1293}
1294
1295NTSTATUS VBoxWddmGetModesForResolution(PDEVICE_EXTENSION DeviceExtension, bool bRebuildTable,
1296 D3DKMDT_2DREGION *pResolution,
1297 VIDEO_MODE_INFORMATION * pModes, uint32_t cModes, uint32_t *pcModes, int32_t *piPreferrableMode)
1298{
1299 VIDEO_MODE_INFORMATION *pAllModes;
1300 uint32_t cAllModes, cAllResolutions;
1301 int32_t iPreferrableMode;
1302 D3DKMDT_2DREGION *pAllResolutions;
1303 VBoxWddmGetModesTable(DeviceExtension, bRebuildTable,
1304 &pAllModes, &cAllModes, &iPreferrableMode,
1305 &pAllResolutions, &cAllResolutions);
1306 NTSTATUS Status = STATUS_SUCCESS;
1307 uint32_t cFound = 0;
1308 int iFoundPreferrableMode = -1;
1309 for (uint32_t i = 0; i < cAllModes; ++i)
1310 {
1311 VIDEO_MODE_INFORMATION *pCur = &pAllModes[i];
1312 if (pResolution->cx == pAllModes[i].VisScreenWidth
1313 && pResolution->cy == pAllModes[i].VisScreenHeight)
1314 {
1315 if (pModes && cModes > cFound)
1316 memcpy(&pModes[cFound], pCur, sizeof (VIDEO_MODE_INFORMATION));
1317 else
1318 Status = STATUS_BUFFER_TOO_SMALL;
1319
1320 if (i == (uint32_t)iPreferrableMode)
1321 iFoundPreferrableMode = cFound;
1322
1323 ++cFound;
1324 }
1325 }
1326
1327 Assert(iFoundPreferrableMode < 0 || cFound > (uint32_t)iFoundPreferrableMode);
1328
1329 *pcModes = cFound;
1330 if (piPreferrableMode)
1331 *piPreferrableMode = iFoundPreferrableMode;
1332
1333 return Status;
1334}
1335
1336#else
1337
1338/* Computes the size of a framebuffer. DualView has a few framebuffers of the computed size. */
1339void VBoxComputeFrameBufferSizes (PDEVICE_EXTENSION PrimaryExtension)
1340{
1341#ifndef VBOX_WITH_HGSMI
1342 ULONG ulAvailable = PrimaryExtension->u.primary.cbVRAM
1343 - PrimaryExtension->u.primary.cbMiniportHeap
1344 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
1345#else
1346 ULONG ulAvailable = PrimaryExtension->u.primary.cbVRAM
1347 - PrimaryExtension->u.primary.cbMiniportHeap
1348 - VBVA_ADAPTER_INFORMATION_SIZE;
1349#endif /* VBOX_WITH_HGSMI */
1350
1351 /* Size of a framebuffer. */
1352
1353 ULONG ulSize = ulAvailable / PrimaryExtension->u.primary.cDisplays;
1354
1355 /* Align down to 4096 bytes. */
1356 ulSize &= ~0xFFF;
1357
1358 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X\n",
1359 PrimaryExtension->u.primary.cbVRAM, PrimaryExtension->u.primary.cDisplays,
1360 ulSize, ulSize * PrimaryExtension->u.primary.cDisplays,
1361 ulAvailable - ulSize * PrimaryExtension->u.primary.cDisplays));
1362
1363#ifndef VBOX_WITH_HGSMI
1364 if (ulSize > VBOX_VIDEO_DISPLAY_INFORMATION_SIZE)
1365 {
1366 /* Compute the size of the framebuffer. */
1367 ulSize -= VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
1368 }
1369 else
1370 {
1371 /* Should not really get here. But still do it safely. */
1372 ulSize = 0;
1373 }
1374#endif /* !VBOX_WITH_HGSMI */
1375
1376 /* Update the primary info. */
1377 PrimaryExtension->u.primary.ulMaxFrameBufferSize = ulSize;
1378#ifndef VBOX_WITH_HGSMI
1379 PrimaryExtension->u.primary.ulDisplayInformationSize = VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
1380#endif /* !VBOX_WITH_HGSMI */
1381
1382 /* Update the per extension info. */
1383 PDEVICE_EXTENSION Extension = PrimaryExtension;
1384 ULONG ulFrameBufferOffset = 0;
1385 while (Extension)
1386 {
1387 Extension->ulFrameBufferOffset = ulFrameBufferOffset;
1388 /* That is assigned when a video mode is set. */
1389 Extension->ulFrameBufferSize = 0;
1390
1391 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: [%d] ulFrameBufferOffset 0x%08X\n",
1392 Extension->iDevice, ulFrameBufferOffset));
1393
1394#ifndef VBOX_WITH_HGSMI
1395 ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize
1396 + PrimaryExtension->u.primary.ulDisplayInformationSize;
1397#else
1398 ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize;
1399#endif /* VBOX_WITH_HGSMI */
1400
1401 Extension = Extension->pNext;
1402 }
1403}
1404
1405#endif
1406
1407int VBoxMapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv, ULONG ulOffset, ULONG ulSize)
1408{
1409 dprintf(("VBoxVideo::VBoxMapAdapterMemory 0x%08X[0x%X]\n", ulOffset, ulSize));
1410
1411 if (!ulSize)
1412 {
1413 dprintf(("Illegal length 0!\n"));
1414 return ERROR_INVALID_PARAMETER;
1415 }
1416
1417 PHYSICAL_ADDRESS FrameBuffer;
1418 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + ulOffset;
1419
1420 PVOID VideoRamBase = NULL;
1421 ULONG VideoRamLength = ulSize;
1422 VP_STATUS Status;
1423#ifndef VBOXWDDM
1424 ULONG inIoSpace = 0;
1425
1426 Status = VideoPortMapMemory (PrimaryExtension, FrameBuffer,
1427 &VideoRamLength, &inIoSpace,
1428 &VideoRamBase);
1429#else
1430 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbMapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1431 FrameBuffer,
1432 VideoRamLength,
1433 FALSE, /* IN BOOLEAN InIoSpace */
1434 FALSE, /* IN BOOLEAN MapToUserMode */
1435 MmNonCached, /* IN MEMORY_CACHING_TYPE CacheType */
1436 &VideoRamBase /*OUT PVOID *VirtualAddress*/
1437 );
1438 Assert(ntStatus == STATUS_SUCCESS);
1439 Status = ntStatus == STATUS_SUCCESS ? NO_ERROR : ERROR_INVALID_PARAMETER; /*<- this is what VideoPortMapMemory returns according to the docs */
1440#endif
1441
1442 if (Status == NO_ERROR)
1443 {
1444 *ppv = VideoRamBase;
1445 }
1446
1447 dprintf(("VBoxVideo::VBoxMapAdapterMemory rc = %d\n", Status));
1448
1449 return Status;
1450}
1451
1452void VBoxUnmapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv, ULONG ulSize)
1453{
1454 dprintf(("VBoxVideo::VBoxMapAdapterMemory\n"));
1455
1456 if (*ppv)
1457 {
1458#ifndef VBOXWDDM
1459 VideoPortUnmapMemory(PrimaryExtension, *ppv, NULL);
1460#else
1461 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbUnmapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1462 *ppv);
1463 Assert(ntStatus == STATUS_SUCCESS);
1464#endif
1465 }
1466
1467 *ppv = NULL;
1468}
1469
1470#ifndef VBOX_WITH_HGSMI
1471
1472# ifdef VBOXWDDM
1473/* sanity check */
1474# error WDDM is supported only for HGSMI-based driver
1475# endif
1476
1477static void vboxQueryConf (PDEVICE_EXTENSION PrimaryExtension, uint32_t u32Index, ULONG *pulValue)
1478{
1479 dprintf(("VBoxVideo::vboxQueryConf: u32Index = %d\n", u32Index));
1480
1481 typedef struct _VBOXVIDEOQCONF32
1482 {
1483 VBOXVIDEOINFOHDR hdrQuery;
1484 VBOXVIDEOINFOQUERYCONF32 query;
1485 VBOXVIDEOINFOHDR hdrEnd;
1486 } VBOXVIDEOQCONF32;
1487
1488 VBOXVIDEOQCONF32 *p = (VBOXVIDEOQCONF32 *)PrimaryExtension->u.primary.pvAdapterInformation;
1489
1490 p->hdrQuery.u8Type = VBOX_VIDEO_INFO_TYPE_QUERY_CONF32;
1491 p->hdrQuery.u8Reserved = 0;
1492 p->hdrQuery.u16Length = sizeof (VBOXVIDEOINFOQUERYCONF32);
1493
1494 p->query.u32Index = u32Index;
1495 p->query.u32Value = 0;
1496
1497 p->hdrEnd.u8Type = VBOX_VIDEO_INFO_TYPE_END;
1498 p->hdrEnd.u8Reserved = 0;
1499 p->hdrEnd.u16Length = 0;
1500
1501 /* Let the host to process the commands. */
1502 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1503 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY);
1504
1505 *pulValue = (ULONG)p->query.u32Value;
1506
1507 dprintf(("VBoxVideo::vboxQueryConf: u32Value = %d\n", p->query.u32Value));
1508}
1509
1510static void vboxSetupAdapterInfo (PDEVICE_EXTENSION PrimaryExtension)
1511{
1512 dprintf(("VBoxVideo::vboxSetupAdapterInfo\n"));
1513
1514 VBOXVIDEOINFOHDR *pHdr;
1515
1516 uint8_t *pu8 = (uint8_t *)PrimaryExtension->u.primary.pvAdapterInformation;
1517
1518 PDEVICE_EXTENSION Extension = PrimaryExtension;
1519 while (Extension)
1520 {
1521 pHdr = (VBOXVIDEOINFOHDR *)pu8;
1522 pu8 += sizeof (VBOXVIDEOINFOHDR);
1523
1524 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_DISPLAY;
1525 pHdr->u8Reserved = 0;
1526 pHdr->u16Length = sizeof (VBOXVIDEOINFODISPLAY);
1527
1528 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8;
1529 pu8 += sizeof (VBOXVIDEOINFODISPLAY);
1530
1531 pDisplay->u32Index = Extension->iDevice;
1532 pDisplay->u32Offset = Extension->ulFrameBufferOffset;
1533 pDisplay->u32FramebufferSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
1534 pDisplay->u32InformationSize = PrimaryExtension->u.primary.ulDisplayInformationSize;
1535
1536 Extension = Extension->pNext;
1537 }
1538
1539
1540 /* The heap description. */
1541 pHdr = (VBOXVIDEOINFOHDR *)pu8;
1542 pu8 += sizeof (VBOXVIDEOINFOHDR);
1543
1544 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_NV_HEAP;
1545 pHdr->u8Reserved = 0;
1546 pHdr->u16Length = sizeof (VBOXVIDEOINFONVHEAP);
1547
1548 VBOXVIDEOINFONVHEAP *pHeap = (VBOXVIDEOINFONVHEAP *)pu8;
1549 pu8 += sizeof (VBOXVIDEOINFONVHEAP);
1550
1551 pHeap->u32HeapOffset = PrimaryExtension->u.primary.cbVRAM
1552 - PrimaryExtension->u.primary.cbMiniportHeap
1553 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
1554 pHeap->u32HeapSize = PrimaryExtension->u.primary.cbMiniportHeap;
1555
1556
1557 /* The END marker. */
1558 pHdr = (VBOXVIDEOINFOHDR *)pu8;
1559 pu8 += sizeof (VBOXVIDEOINFOHDR);
1560
1561 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_END;
1562 pHdr->u8Reserved = 0;
1563 pHdr->u16Length = 0;
1564
1565 /* Inform the host about the display configuration. */
1566 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1567 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY);
1568
1569 dprintf(("VBoxVideo::vboxSetupAdapterInfo finished\n"));
1570}
1571
1572/**
1573 * Helper function to register secondary displays (DualView). Note that this will not
1574 * be available on pre-XP versions, and some editions on XP will fail because they are
1575 * intentionally crippled.
1576 */
1577VOID VBoxSetupDisplays(PDEVICE_EXTENSION PrimaryExtension, PVIDEO_PORT_CONFIG_INFO pConfigInfo, ULONG AdapterMemorySize)
1578{
1579 VP_STATUS rc = NO_ERROR;
1580
1581 dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
1582 PrimaryExtension));
1583
1584 /* Preinitialize the primary extension. */
1585 PrimaryExtension->pNext = NULL;
1586 PrimaryExtension->pPrimary = PrimaryExtension;
1587 PrimaryExtension->iDevice = 0;
1588 PrimaryExtension->ulFrameBufferOffset = 0;
1589 PrimaryExtension->ulFrameBufferSize = 0;
1590 PrimaryExtension->u.primary.ulVbvaEnabled = 0;
1591 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1592 PrimaryExtension->u.primary.cDisplays = 1;
1593 PrimaryExtension->u.primary.cbVRAM = AdapterMemorySize;
1594 PrimaryExtension->u.primary.cbMiniportHeap = 0;
1595 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
1596 PrimaryExtension->u.primary.pvAdapterInformation = NULL;
1597 PrimaryExtension->u.primary.ulMaxFrameBufferSize = 0;
1598 PrimaryExtension->u.primary.ulDisplayInformationSize = 0;
1599
1600 /* Verify whether the HW supports VirtualBox extensions. */
1601 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1602 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_VBOX_VIDEO);
1603
1604 if (VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA) == VBE_DISPI_ID_VBOX_VIDEO)
1605 {
1606 PrimaryExtension->u.primary.bVBoxVideoSupported = TRUE;
1607 }
1608
1609 dprintf(("VBoxVideo::VBoxSetupDisplays: bVBoxVideoSupported = %d\n",
1610 PrimaryExtension->u.primary.bVBoxVideoSupported));
1611
1612 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1613 {
1614 /* Map the adapter information. It will be needed to query some configuration values. */
1615 rc = VBoxMapAdapterMemory (PrimaryExtension,
1616 &PrimaryExtension->u.primary.pvAdapterInformation,
1617 PrimaryExtension->u.primary.cbVRAM - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE,
1618 VBOX_VIDEO_ADAPTER_INFORMATION_SIZE
1619 );
1620 if (rc != NO_ERROR)
1621 {
1622 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
1623 rc));
1624
1625 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1626 }
1627 }
1628
1629 /* Setup the non-volatile heap and the adapter memory. */
1630 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1631 {
1632 /* Query the size of the non-volatile heap. */
1633 ULONG cbMiniportHeap = 0;
1634 vboxQueryConf (PrimaryExtension, VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE, &cbMiniportHeap);
1635
1636 /* Do not allow too big heap. 50% of VRAM should be enough. */
1637 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 2 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
1638
1639 if (cbMiniportHeap > cbMiniportHeapMaxSize)
1640 {
1641 cbMiniportHeap = cbMiniportHeapMaxSize;
1642 }
1643
1644 /* Round up to 4096. */
1645 PrimaryExtension->u.primary.cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
1646
1647 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
1648 cbMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap, cbMiniportHeapMaxSize));
1649
1650 /* Map the heap region and the adapter information area.
1651 *
1652 * Note: the heap will be used by display drivers, possibly by a few instances
1653 * in multimonitor configuration, but the memory is mapped here ones.
1654 * It is assumed that all display drivers and the miniport has the SAME
1655 * virtual address space.
1656 *
1657 */
1658 rc = VBoxMapAdapterMemory (PrimaryExtension,
1659 &PrimaryExtension->u.primary.pvMiniportHeap,
1660 PrimaryExtension->u.primary.cbVRAM
1661 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE
1662 - PrimaryExtension->u.primary.cbMiniportHeap,
1663 PrimaryExtension->u.primary.cbMiniportHeap
1664 );
1665
1666 if (rc != NO_ERROR)
1667 {
1668 PrimaryExtension->u.primary.cbMiniportHeap = 0;
1669 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1670 }
1671 }
1672
1673 /* Check whether the guest supports multimonitors. */
1674 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1675 {
1676 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
1677 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
1678
1679 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
1680 if (vboxQueryWinVersion() > WINNT4)
1681 {
1682 /* This bluescreens on NT4, hence the above version check */
1683 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
1684 (PrimaryExtension,
1685 (PUCHAR)"VideoPortCreateSecondaryDisplay");
1686 }
1687
1688 if (pfnCreateSecondaryDisplay != NULL)
1689 {
1690 /* Query the configured number of displays. */
1691 ULONG cDisplays = 0;
1692 vboxQueryConf (PrimaryExtension, VBOX_VIDEO_QCI32_MONITOR_COUNT, &cDisplays);
1693
1694 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
1695 cDisplays));
1696
1697 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
1698 {
1699 /* Host reported some bad value. Continue in the 1 screen mode. */
1700 cDisplays = 1;
1701 }
1702
1703 PDEVICE_EXTENSION pPrev = PrimaryExtension;
1704
1705 ULONG iDisplay;
1706 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
1707 {
1708 PDEVICE_EXTENSION SecondaryExtension = NULL;
1709 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
1710
1711 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
1712 rc, SecondaryExtension));
1713
1714 if (rc != NO_ERROR)
1715 {
1716 break;
1717 }
1718
1719 SecondaryExtension->pNext = NULL;
1720 SecondaryExtension->pPrimary = PrimaryExtension;
1721 SecondaryExtension->iDevice = iDisplay;
1722 SecondaryExtension->ulFrameBufferOffset = 0;
1723 SecondaryExtension->ulFrameBufferSize = 0;
1724 SecondaryExtension->u.secondary.bEnabled = FALSE;
1725
1726 /* Update the list pointers. */
1727 pPrev->pNext = SecondaryExtension;
1728 pPrev = SecondaryExtension;
1729
1730 /* Take the successfully created display into account. */
1731 PrimaryExtension->u.primary.cDisplays++;
1732 }
1733
1734 /* Failure to create secondary displays is not fatal */
1735 rc = NO_ERROR;
1736 }
1737 }
1738
1739 /* Now when the number of monitors is known and extensions are created,
1740 * calculate the layout of framebuffers.
1741 */
1742 VBoxComputeFrameBufferSizes (PrimaryExtension);
1743
1744 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1745 {
1746 /* Setup the information for the host. */
1747 vboxSetupAdapterInfo (PrimaryExtension);
1748 }
1749 else
1750 {
1751 /* Unmap the memory if VBoxVideo is not supported. */
1752 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap);
1753 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvAdapterInformation, VBOX_VIDEO_ADAPTER_INFORMATION_SIZE);
1754 }
1755
1756 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
1757}
1758#endif /* !VBOX_WITH_HGSMI */
1759
1760#ifndef VBOXWDDM
1761
1762VP_STATUS VBoxVideoFindAdapter(IN PVOID HwDeviceExtension,
1763 IN PVOID HwContext, IN PWSTR ArgumentString,
1764 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
1765 OUT PUCHAR Again)
1766{
1767 VP_STATUS rc;
1768 USHORT DispiId;
1769 ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
1770 VIDEO_ACCESS_RANGE AccessRanges[] =
1771 {
1772 {
1773 {0, VBE_DISPI_LFB_PHYSICAL_ADDRESS},
1774 VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES,
1775 0,
1776 FALSE,
1777 FALSE,
1778 0
1779 }
1780 };
1781
1782 dprintf(("VBoxVideo::VBoxVideoFindAdapter %p\n", HwDeviceExtension));
1783
1784#ifdef VBOX_WITH_HGSMI
1785 VBoxSetupVideoPortFunctions((PDEVICE_EXTENSION)HwDeviceExtension, &((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.VideoPortProcs, ConfigInfo);
1786#endif
1787
1788 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1789 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
1790 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
1791 if (DispiId == VBE_DISPI_ID2)
1792 {
1793 dprintf(("VBoxVideo::VBoxVideoFoundAdapter: found the VBE card\n"));
1794 /*
1795 * Write some hardware information to registry, so that
1796 * it's visible in Windows property dialog.
1797 */
1798
1799 rc = VideoPortSetRegistryParameters(
1800 HwDeviceExtension,
1801 L"HardwareInformation.ChipType",
1802 VBoxChipType,
1803 sizeof(VBoxChipType));
1804
1805 rc = VideoPortSetRegistryParameters(
1806 HwDeviceExtension,
1807 L"HardwareInformation.DacType",
1808 VBoxDACType,
1809 sizeof(VBoxDACType));
1810
1811 /*
1812 * Query the adapter's memory size. It's a bit of a hack, we just read
1813 * an ULONG from the data port without setting an index before.
1814 */
1815 AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
1816 rc = VideoPortSetRegistryParameters(
1817 HwDeviceExtension,
1818 L"HardwareInformation.MemorySize",
1819 &AdapterMemorySize,
1820 sizeof(ULONG));
1821
1822 rc = VideoPortSetRegistryParameters(
1823 HwDeviceExtension,
1824 L"HardwareInformation.AdapterString",
1825 VBoxAdapterString,
1826 sizeof(VBoxAdapterString));
1827
1828 rc = VideoPortSetRegistryParameters(
1829 HwDeviceExtension,
1830 L"HardwareInformation.BiosString",
1831 VBoxBiosString,
1832 sizeof(VBoxBiosString));
1833#ifdef VBOX_WITH_HGSMI
1834 if (VBoxHGSMIIsSupported ((PDEVICE_EXTENSION)HwDeviceExtension))
1835 {
1836 dprintf(("VBoxVideo::VBoxVideoFindAdapter: calling VideoPortGetAccessRanges\n"));
1837
1838 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.IOPortHost = (RTIOPORT)VGA_PORT_HGSMI_HOST;
1839 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.IOPortGuest = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
1840
1841 VIDEO_ACCESS_RANGE tmpRanges[4];
1842 ULONG slot = 0;
1843
1844 VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));
1845
1846 /* need to call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up */
1847 VP_STATUS status;
1848 if (vboxQueryWinVersion() == WINNT4)
1849 {
1850 /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
1851 * and needs PCI ids for a successful VideoPortGetAccessRanges call.
1852 */
1853 ULONG vendorId = 0x80EE;
1854 ULONG deviceId = 0xBEEF;
1855 status = VideoPortGetAccessRanges(HwDeviceExtension,
1856 0,
1857 NULL,
1858 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1859 tmpRanges,
1860 &vendorId,
1861 &deviceId,
1862 &slot);
1863 }
1864 else
1865 {
1866 status = VideoPortGetAccessRanges(HwDeviceExtension,
1867 0,
1868 NULL,
1869 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1870 tmpRanges,
1871 NULL,
1872 NULL,
1873 &slot);
1874 }
1875 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortGetAccessRanges status 0x%x\n", status));
1876
1877 /* no matter what we get with VideoPortGetAccessRanges, we assert the default ranges */
1878 }
1879#else
1880 rc = VideoPortVerifyAccessRanges(HwDeviceExtension, 1, AccessRanges);
1881 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortVerifyAccessRanges returned 0x%x\n", rc));
1882 // @todo for some reason, I get an ERROR_INVALID_PARAMETER from NT4 SP0
1883 // It does not seem to like getting me these port addresses. So I just
1884 // pretend success to make the driver work.
1885 rc = NO_ERROR;
1886#endif /* VBOX_WITH_HGSMI */
1887
1888#ifndef VBOX_WITH_HGSMI
1889 /* Initialize VBoxGuest library */
1890 rc = VbglInit ();
1891
1892 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
1893
1894 /* Setup the Device Extension and if possible secondary displays. */
1895 VBoxSetupDisplays((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
1896#else
1897 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
1898 rc = VbglInit ();
1899
1900 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
1901 * code will be ifdef'ed and later removed.
1902 * The host will however support both old and new interface to keep compatibility
1903 * with old guest additions.
1904 */
1905 VBoxSetupDisplaysHGSMI((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
1906
1907 if (((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.bHGSMI)
1908 {
1909 LogRel(("VBoxVideo: using HGSMI\n"));
1910 }
1911#endif /* VBOX_WITH_HGSMI */
1912
1913 // pretend success to make the driver work.
1914 rc = NO_ERROR;
1915 } else
1916 {
1917 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
1918 rc = ERROR_DEV_NOT_EXIST;
1919 }
1920 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
1921 return rc;
1922}
1923
1924/**
1925 * VBoxVideoInitialize
1926 *
1927 * Performs the first initialization of the adapter, after the HAL has given
1928 * up control of the video hardware to the video port driver.
1929 */
1930BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
1931{
1932 VP_STATUS status;
1933
1934 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
1935
1936 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1937
1938 /* Initialize the request pointer. */
1939 pDevExt->u.primary.pvReqFlush = NULL;
1940
1941#ifndef VBOX_WITH_MULTIMONITOR_FIX
1942 /*
1943 * Get the last custom resolution
1944 */
1945 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1946 L"CustomXRes",
1947 FALSE,
1948 VBoxRegistryCallback,
1949 &gCustomXRes);
1950 if (status != NO_ERROR)
1951 gCustomXRes = 0;
1952 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1953 L"CustomYRes",
1954 FALSE,
1955 VBoxRegistryCallback,
1956 &gCustomYRes);
1957 if (status != NO_ERROR)
1958 gCustomYRes = 0;
1959 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1960 L"CustomBPP",
1961 FALSE,
1962 VBoxRegistryCallback,
1963 &gCustomBPP);
1964 if (status != NO_ERROR)
1965 gCustomBPP = 0;
1966
1967 dprintf(("VBoxVideo: got stored custom resolution %dx%dx%d\n", gCustomXRes, gCustomYRes, gCustomBPP));
1968#else
1969 /* Initialize all custom modes to the 800x600x32. */
1970 initVideoModeInformation(&CustomVideoModes[0], 800, 600, 32, 0, 0);
1971
1972 int iCustomMode;
1973 for (iCustomMode = 1; iCustomMode < RT_ELEMENTS(CustomVideoModes); iCustomMode++)
1974 {
1975 CustomVideoModes[iCustomMode] = CustomVideoModes[0];
1976 }
1977
1978 /* Load stored custom resolution from the registry. */
1979 PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
1980 for (iCustomMode = 0; iCustomMode < DeviceExtension->pPrimary->u.primary.cDisplays; iCustomMode++)
1981 {
1982 /*
1983 * Get the last custom resolution
1984 */
1985 ULONG CustomXRes = 0, CustomYRes = 0, CustomBPP = 0;
1986
1987 if (iCustomMode == 0)
1988 {
1989 /* Name without a suffix */
1990 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1991 L"CustomXRes",
1992 FALSE,
1993 VBoxRegistryCallback,
1994 &CustomXRes);
1995 if (status != NO_ERROR)
1996 CustomXRes = 0;
1997 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1998 L"CustomYRes",
1999 FALSE,
2000 VBoxRegistryCallback,
2001 &CustomYRes);
2002 if (status != NO_ERROR)
2003 CustomYRes = 0;
2004 status = VideoPortGetRegistryParameters(HwDeviceExtension,
2005 L"CustomBPP",
2006 FALSE,
2007 VBoxRegistryCallback,
2008 &CustomBPP);
2009 if (status != NO_ERROR)
2010 CustomBPP = 0;
2011 }
2012 else
2013 {
2014 wchar_t keyname[32];
2015 swprintf(keyname, L"CustomXRes%d", iCustomMode);
2016 status = VideoPortGetRegistryParameters(HwDeviceExtension,
2017 keyname,
2018 FALSE,
2019 VBoxRegistryCallback,
2020 &CustomXRes);
2021 if (status != NO_ERROR)
2022 CustomXRes = 0;
2023 swprintf(keyname, L"CustomYRes%d", iCustomMode);
2024 status = VideoPortGetRegistryParameters(HwDeviceExtension,
2025 keyname,
2026 FALSE,
2027 VBoxRegistryCallback,
2028 &CustomYRes);
2029 if (status != NO_ERROR)
2030 CustomYRes = 0;
2031 swprintf(keyname, L"CustomBPP%d", iCustomMode);
2032 status = VideoPortGetRegistryParameters(HwDeviceExtension,
2033 keyname,
2034 FALSE,
2035 VBoxRegistryCallback,
2036 &CustomBPP);
2037 if (status != NO_ERROR)
2038 CustomBPP = 0;
2039 }
2040
2041 dprintf(("VBoxVideo: got stored custom resolution[%d] %dx%dx%d\n", iCustomMode, CustomXRes, CustomYRes, CustomBPP));
2042
2043 if (CustomXRes || CustomYRes || CustomBPP)
2044 {
2045 if (CustomXRes == 0)
2046 {
2047 CustomXRes = CustomVideoModes[iCustomMode].VisScreenWidth;
2048 }
2049 if (CustomYRes == 0)
2050 {
2051 CustomYRes = CustomVideoModes[iCustomMode].VisScreenHeight;
2052 }
2053 if (CustomBPP == 0)
2054 {
2055 CustomBPP = CustomVideoModes[iCustomMode].BitsPerPlane;
2056 }
2057
2058 initVideoModeInformation(&CustomVideoModes[iCustomMode], CustomXRes, CustomYRes, CustomBPP, 0, 0);
2059 }
2060 }
2061#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2062
2063 return TRUE;
2064}
2065
2066# if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL)
2067
2068BOOLEAN VBoxVideoInterrupt(PVOID HwDeviceExtension)
2069{
2070 PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2071 PDEVICE_EXTENSION PrimaryExtension = devExt->pPrimary;
2072 if (PrimaryExtension)
2073 {
2074 if (PrimaryExtension->u.primary.pHostFlags) /* If HGSMI is enabled at all. */
2075 {
2076 uint32_t flags = PrimaryExtension->u.primary.pHostFlags->u32HostFlags;
2077 if((flags & HGSMIHOSTFLAGS_IRQ) != 0)
2078 {
2079 if((flags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0)
2080 {
2081 /* schedule a DPC*/
2082 BOOLEAN bResult = PrimaryExtension->u.primary.VideoPortProcs.pfnQueueDpc(PrimaryExtension, VBoxVideoHGSMIDpc, (PVOID)1);
2083 Assert(bResult);
2084 }
2085 /* clear the IRQ */
2086 HGSMIClearIrq (PrimaryExtension);
2087 return TRUE;
2088 }
2089 }
2090 }
2091 return FALSE;
2092}
2093# endif /* #if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL) */
2094#endif /* #ifndef VBOXWDDM */
2095/**
2096 * Send a request to the host to make the absolute pointer visible
2097 */
2098static BOOLEAN ShowPointer(PVOID HwDeviceExtension)
2099{
2100 BOOLEAN Result = TRUE;
2101
2102 /* Use primary device extension, because the show pointer request should be processed
2103 * in vboxUpdatePointerShape regardless of the device. */
2104#ifndef VBOXWDDM
2105 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary;
2106#else
2107 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
2108#endif
2109
2110 if (DEV_MOUSE_HIDDEN(PrimaryExtension))
2111 {
2112 // tell the host to use the guest's pointer
2113 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
2114
2115 /* Visible and No Shape means Show the pointer.
2116 * It is enough to init only this field.
2117 */
2118 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
2119
2120#ifndef VBOX_WITH_HGSMI
2121 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
2122#else
2123 Result = vboxUpdatePointerShape(PrimaryExtension, &PointerAttributes, sizeof (PointerAttributes));
2124#endif /* VBOX_WITH_HGSMI */
2125
2126 if (Result)
2127 DEV_SET_MOUSE_SHOWN(PrimaryExtension);
2128 else
2129 dprintf(("VBoxVideo::ShowPointer: Could not show the hardware pointer -> fallback\n"));
2130 }
2131 return Result;
2132}
2133
2134#ifndef VBOXWDDM
2135/**
2136 * VBoxVideoStartIO
2137 *
2138 * Processes the specified Video Request Packet.
2139 */
2140BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
2141 PVIDEO_REQUEST_PACKET RequestPacket)
2142{
2143 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2144
2145 BOOLEAN Result;
2146
2147// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
2148
2149 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2150
2151 switch (RequestPacket->IoControlCode)
2152 {
2153 case IOCTL_VIDEO_SET_CURRENT_MODE:
2154 {
2155 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
2156 {
2157 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2158 return TRUE;
2159 }
2160 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
2161 (PVIDEO_MODE)RequestPacket->InputBuffer,
2162 RequestPacket->StatusBlock);
2163 break;
2164 }
2165
2166 case IOCTL_VIDEO_RESET_DEVICE:
2167 {
2168 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
2169 RequestPacket->StatusBlock);
2170 break;
2171 }
2172
2173 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
2174 {
2175 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
2176 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
2177 {
2178 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2179 return TRUE;
2180 }
2181 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
2182 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
2183 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
2184 RequestPacket->StatusBlock);
2185 break;
2186 }
2187
2188 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
2189 {
2190 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
2191 {
2192 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2193 return TRUE;
2194 }
2195 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
2196 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
2197 RequestPacket->StatusBlock);
2198 break;
2199 }
2200
2201 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
2202 {
2203 PVIDEO_SHARE_MEMORY pShareMemory;
2204 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
2205 PHYSICAL_ADDRESS shareAddress;
2206 PVOID virtualAddress = NULL;
2207 ULONG sharedViewSize;
2208 ULONG inIoSpace = 0;
2209 VP_STATUS status;
2210
2211 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
2212
2213 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
2214 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
2215
2216 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
2217 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2218 Result = FALSE;
2219 break;
2220 }
2221
2222 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
2223
2224 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
2225 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
2226
2227 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INVALID_PARAMETER %x:%x size %x\n", pShareMemory->ViewOffset, pShareMemory->ViewSize, pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize));
2228 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
2229 Result = FALSE;
2230 break;
2231 }
2232
2233 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
2234
2235 virtualAddress = pShareMemory->ProcessHandle;
2236 sharedViewSize = pShareMemory->ViewSize;
2237
2238 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
2239
2240 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
2241 if (status != NO_ERROR)
2242 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
2243 Result = (status == NO_ERROR);
2244
2245 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
2246 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
2247 pShareMemoryInformation->VirtualAddress = virtualAddress;
2248 pShareMemoryInformation->SharedViewSize = sharedViewSize;
2249 break;
2250 }
2251
2252 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
2253 {
2254 PVIDEO_SHARE_MEMORY pShareMemory;
2255 VP_STATUS status;
2256
2257 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
2258
2259 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
2260 {
2261 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
2262 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2263 Result = FALSE;
2264 break;
2265 }
2266
2267 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
2268
2269 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
2270 if (status != NO_ERROR)
2271 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
2272 Result = (status == NO_ERROR);
2273 break;
2274 }
2275
2276 /*
2277 * The display driver asks us how many video modes we support
2278 * so that it can supply an appropriate buffer for the next call.
2279 */
2280 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
2281 {
2282 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
2283 {
2284 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2285 return TRUE;
2286 }
2287 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
2288 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
2289 RequestPacket->StatusBlock);
2290 break;
2291 }
2292
2293 /*
2294 * The display driver asks us to provide a list of supported video modes
2295 * into a buffer it has allocated.
2296 */
2297 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
2298 {
2299 if (RequestPacket->OutputBufferLength <
2300 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
2301 {
2302 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2303 return TRUE;
2304 }
2305 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
2306 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
2307 RequestPacket->StatusBlock);
2308 break;
2309 }
2310
2311 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
2312 {
2313 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
2314 RequestPacket->InputBufferLength <
2315 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
2316 sizeof(VIDEO_CLUT))
2317 {
2318 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2319 return TRUE;
2320 }
2321 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
2322 (PVIDEO_CLUT)RequestPacket->InputBuffer,
2323 RequestPacket->StatusBlock);
2324 break;
2325 }
2326
2327 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
2328 {
2329 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
2330 {
2331 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2332 return TRUE;
2333 }
2334 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
2335 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
2336 RequestPacket->StatusBlock);
2337 break;
2338 }
2339
2340 // show the pointer
2341 case IOCTL_VIDEO_ENABLE_POINTER:
2342 {
2343 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
2344 // find out whether the host wants absolute positioning
2345 /// @todo this is now obsolete - remove it?
2346 if (vboxQueryHostWantsAbsolute())
2347 Result = ShowPointer(HwDeviceExtension);
2348 else
2349 {
2350 // fallback to software pointer
2351 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2352 Result = FALSE;
2353 }
2354 break;
2355 }
2356
2357 // hide the pointer
2358 case IOCTL_VIDEO_DISABLE_POINTER:
2359 {
2360 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
2361 // find out whether the host wants absolute positioning
2362 if (vboxQueryHostWantsAbsolute())
2363 {
2364 // tell the host to hide pointer
2365 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
2366
2367 /* Enable == 0 means no shape, not visible.
2368 * It is enough to init only this field.
2369 */
2370 PointerAttributes.Enable = 0;
2371
2372#ifndef VBOX_WITH_HGSMI
2373 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
2374#else
2375 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, &PointerAttributes, sizeof (PointerAttributes));
2376#endif /* VBOX_WITH_HGSMI */
2377
2378 if (Result)
2379 DEV_SET_MOUSE_HIDDEN((PDEVICE_EXTENSION)HwDeviceExtension);
2380 else
2381 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
2382 } else
2383 {
2384 // fallback to software pointer
2385 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2386 Result = FALSE;
2387 }
2388 break;
2389 }
2390
2391 /*
2392 * Change the pointer shape
2393 */
2394 case IOCTL_VIDEO_SET_POINTER_ATTR:
2395 {
2396 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
2397 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
2398 {
2399 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
2400 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2401 return TRUE;
2402 }
2403 // find out whether the host wants absolute positioning
2404 if (vboxQueryHostWantsAbsolute())
2405 {
2406 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
2407#if 0
2408 dprintf(("Pointer shape information:\n"
2409 "\tFlags: %d\n"
2410 "\tWidth: %d\n"
2411 "\tHeight: %d\n"
2412 "\tWidthInBytes: %d\n"
2413 "\tEnable: %d\n"
2414 "\tColumn: %d\n"
2415 "\tRow: %d\n",
2416 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
2417 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
2418 pPointerAttributes->Row));
2419 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
2420#endif
2421#ifndef VBOX_WITH_HGSMI
2422 Result = vboxUpdatePointerShape(pPointerAttributes, RequestPacket->InputBufferLength);
2423#else
2424 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, pPointerAttributes, RequestPacket->InputBufferLength);
2425#endif /* VBOX_WITH_HGSMI */
2426 if (!Result)
2427 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
2428 } else
2429 {
2430 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
2431 // fallback to software pointer
2432 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2433 Result = FALSE;
2434 }
2435 break;
2436 }
2437
2438 // query pointer information
2439 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
2440 {
2441 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
2442 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2443 Result = FALSE;
2444 break;
2445 }
2446
2447 // set the pointer position
2448 case IOCTL_VIDEO_SET_POINTER_POSITION:
2449 {
2450 // find out whether the host wants absolute positioning
2451 /// @todo this is now obsolete - remove it?
2452 if (vboxQueryHostWantsAbsolute())
2453 Result = ShowPointer(HwDeviceExtension);
2454 else
2455 {
2456 // fallback to software pointer
2457 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2458 Result = FALSE;
2459 }
2460 break;
2461 }
2462
2463 // query the pointer position
2464 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
2465 {
2466 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
2467 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
2468 {
2469 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2470 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2471 return TRUE;
2472 }
2473 Result = FALSE;
2474 uint16_t mousePosX;
2475 uint16_t mousePosY;
2476 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
2477 {
2478 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
2479 PVIDEO_MODE_INFORMATION ModeInfo;
2480 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
2481 // map from 0xFFFF to the current resolution
2482 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
2483 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
2484 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
2485 Result = TRUE;
2486 }
2487 if (!Result)
2488 {
2489 // fallback to software pointer
2490 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2491 }
2492 break;
2493 }
2494
2495 // Determine hardware cursor capabilities. We will always report that we are
2496 // very capable even though the host might not want to do pointer integration.
2497 // This is done because we can still return errors on the actual calls later to
2498 // make the display driver go to the fallback routines.
2499 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
2500 {
2501 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
2502 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
2503 {
2504 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2505 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2506 return TRUE;
2507 }
2508 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
2509 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
2510 VIDEO_MODE_COLOR_POINTER |
2511 VIDEO_MODE_MONO_POINTER;
2512 // for now we go with 64x64 cursors
2513 pCaps->MaxWidth = 64;
2514 pCaps->MaxHeight = 64;
2515 // that doesn't seem to be relevant, VBoxDisp doesn't use it
2516 pCaps->HWPtrBitmapStart = -1;
2517 pCaps->HWPtrBitmapEnd = -1;
2518 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
2519 Result = TRUE;
2520 break;
2521 }
2522
2523 /* Attach/detach DualView devices */
2524 case IOCTL_VIDEO_SWITCH_DUALVIEW:
2525 {
2526 ULONG ulAttach;
2527
2528 ulAttach = *((PULONG)RequestPacket->InputBuffer);
2529 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
2530
2531 if (pDevExt->iDevice > 0)
2532 {
2533 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
2534 }
2535 Result = TRUE;
2536 break;
2537 }
2538
2539 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
2540 {
2541 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
2542
2543 if (pDevExt->pPrimary->u.primary.bVBoxVideoSupported)
2544 {
2545 /* The display driver must have prepared the monitor information. */
2546 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
2547 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE + pDevExt->iDevice);
2548 }
2549 else
2550 {
2551 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2552 }
2553 Result = pDevExt->pPrimary->u.primary.bVBoxVideoSupported;
2554 break;
2555 }
2556
2557#ifndef VBOX_WITH_HGSMI
2558 case IOCTL_VIDEO_QUERY_DISPLAY_INFO:
2559 {
2560 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_DISPLAY_INFO\n"));
2561
2562 if (RequestPacket->OutputBufferLength < sizeof(QUERYDISPLAYINFORESULT))
2563 {
2564 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2565 RequestPacket->OutputBufferLength, sizeof(QUERYDISPLAYINFORESULT)));
2566 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2567 return FALSE;
2568 }
2569
2570 QUERYDISPLAYINFORESULT *pDispInfo = (QUERYDISPLAYINFORESULT *)RequestPacket->OutputBuffer;
2571
2572 pDispInfo->iDevice = pDevExt->iDevice;
2573 pDispInfo->u32DisplayInfoSize = pDevExt->pPrimary->u.primary.ulDisplayInformationSize;
2574
2575 RequestPacket->StatusBlock->Information = sizeof(QUERYDISPLAYINFORESULT);
2576 Result = TRUE;
2577
2578 break;
2579 }
2580#endif /* !VBOX_WITH_HGSMI */
2581
2582 case IOCTL_VIDEO_VBVA_ENABLE:
2583 {
2584 int rc;
2585 ULONG ulEnable;
2586
2587 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
2588
2589 if (RequestPacket->InputBufferLength < sizeof(ULONG))
2590 {
2591 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
2592 RequestPacket->InputBufferLength, sizeof(ULONG)));
2593 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2594 return FALSE;
2595 }
2596
2597 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
2598 {
2599 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2600 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
2601 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2602 return FALSE;
2603 }
2604
2605 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
2606 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
2607
2608 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
2609 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Rrc\n", rc));
2610
2611 if (RT_FAILURE (rc))
2612 {
2613 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
2614 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2615 return FALSE;
2616 }
2617
2618 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
2619 Result = TRUE;
2620
2621 break;
2622 }
2623
2624 /* Private ioctls */
2625 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
2626 {
2627 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
2628 int rc;
2629
2630 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
2631 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
2632 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
2633 {
2634 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
2635 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
2636 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2637 return FALSE;
2638 }
2639 /*
2640 * Inform the host about the visible region
2641 */
2642 VMMDevVideoSetVisibleRegion *req = NULL;
2643
2644 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2645 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
2646 VMMDevReq_VideoSetVisibleRegion);
2647
2648 if (RT_SUCCESS(rc))
2649 {
2650 req->cRect = cRect;
2651 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
2652
2653 rc = VbglGRPerform (&req->header);
2654
2655 if (RT_SUCCESS(rc))
2656 {
2657 Result = TRUE;
2658 break;
2659 }
2660 }
2661
2662 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x\n", rc));
2663 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2664 return FALSE;
2665 }
2666
2667#ifdef VBOX_WITH_HGSMI
2668 case IOCTL_VIDEO_QUERY_HGSMI_INFO:
2669 {
2670 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_HGSMI_INFO\n"));
2671
2672 if (RequestPacket->OutputBufferLength < sizeof(QUERYHGSMIRESULT))
2673 {
2674 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2675 RequestPacket->OutputBufferLength, sizeof(QUERYHGSMIRESULT)));
2676 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2677 return FALSE;
2678 }
2679
2680 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2681 {
2682 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2683 return FALSE;
2684 }
2685
2686 QUERYHGSMIRESULT *pInfo = (QUERYHGSMIRESULT *)RequestPacket->OutputBuffer;
2687
2688 pInfo->iDevice = pDevExt->iDevice;
2689 pInfo->ulFlags = 0;
2690
2691 /* Describes VRAM chunk for this display device. */
2692 pInfo->areaDisplay = pDevExt->areaDisplay;
2693
2694 pInfo->u32DisplayInfoSize = VBVA_DISPLAY_INFORMATION_SIZE;
2695 pInfo->u32MinVBVABufferSize = VBVA_MIN_BUFFER_SIZE;
2696
2697 pInfo->IOPortGuestCommand = pDevExt->pPrimary->u.primary.IOPortGuest;
2698
2699 RequestPacket->StatusBlock->Information = sizeof(QUERYHGSMIRESULT);
2700 Result = TRUE;
2701
2702 break;
2703 }
2704 case IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS:
2705 {
2706 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS\n"));
2707
2708 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCALLBACKS))
2709 {
2710 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2711 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCALLBACKS)));
2712 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2713 return FALSE;
2714 }
2715
2716 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2717 {
2718 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2719 return FALSE;
2720 }
2721
2722 HGSMIQUERYCALLBACKS *pInfo = (HGSMIQUERYCALLBACKS *)RequestPacket->OutputBuffer;
2723
2724 pInfo->hContext = pDevExt;
2725 pInfo->pfnCompletionHandler = hgsmiHostCmdComplete;
2726 pInfo->pfnRequestCommandsHandler = hgsmiHostCmdRequest;
2727
2728 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCALLBACKS);
2729 Result = TRUE;
2730 break;
2731 }
2732 case IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS:
2733 {
2734 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS\n"));
2735
2736 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCPORTPROCS))
2737 {
2738 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2739 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCPORTPROCS)));
2740 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2741 return FALSE;
2742 }
2743
2744 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2745 {
2746 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2747 return FALSE;
2748 }
2749
2750 HGSMIQUERYCPORTPROCS *pInfo = (HGSMIQUERYCPORTPROCS *)RequestPacket->OutputBuffer;
2751 pInfo->pContext = pDevExt->pPrimary;
2752 pInfo->VideoPortProcs = pDevExt->pPrimary->u.primary.VideoPortProcs;
2753
2754 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCPORTPROCS);
2755 Result = TRUE;
2756 break;
2757 }
2758 case IOCTL_VIDEO_HGSMI_HANDLER_ENABLE:
2759 {
2760 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_HANDLER_ENABLE\n"));
2761
2762 if (RequestPacket->InputBufferLength< sizeof(HGSMIHANDLERENABLE))
2763 {
2764 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2765 RequestPacket->InputBufferLength, sizeof(HGSMIHANDLERENABLE)));
2766 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2767 return FALSE;
2768 }
2769
2770 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2771 {
2772 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2773 return FALSE;
2774 }
2775
2776 HGSMIHANDLERENABLE *pInfo = (HGSMIHANDLERENABLE *)RequestPacket->InputBuffer;
2777
2778 int rc = vboxVBVAChannelDisplayEnable(pDevExt->pPrimary,
2779 pDevExt->iDevice,
2780 pInfo->u8Channel);
2781 if(RT_FAILURE(rc))
2782 {
2783 RequestPacket->StatusBlock->Status = ERROR_INVALID_NAME;
2784 }
2785 Result = TRUE;
2786 break;
2787 }
2788 case IOCTL_VIDEO_HGSMI_HANDLER_DISABLE:
2789 {
2790 /* TODO: implement */
2791 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2792 {
2793 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2794 return FALSE;
2795 }
2796 break;
2797 }
2798# ifdef VBOX_WITH_VIDEOHWACCEL
2799 case IOCTL_VIDEO_VHWA_QUERY_INFO:
2800 {
2801 if (RequestPacket->OutputBufferLength < sizeof (VHWAQUERYINFO))
2802 {
2803 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2804 RequestPacket->OutputBufferLength, sizeof(VHWAQUERYINFO)));
2805 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2806 return FALSE;
2807 }
2808
2809 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2810 {
2811 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2812 return FALSE;
2813 }
2814
2815 VHWAQUERYINFO *pInfo = (VHWAQUERYINFO *)RequestPacket->OutputBuffer;
2816 pInfo->offVramBase = (ULONG_PTR)pDevExt->ulFrameBufferOffset;
2817 RequestPacket->StatusBlock->Information = sizeof (VHWAQUERYINFO);
2818 Result = TRUE;
2819 break;
2820 }
2821# endif
2822#endif /* VBOX_WITH_HGSMI */
2823 default:
2824 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
2825 RequestPacket->IoControlCode,
2826 (RequestPacket->IoControlCode >> 2) & 0xFFF,
2827 (RequestPacket->IoControlCode >> 2) & 0xFFF));
2828 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2829 return FALSE;
2830 }
2831
2832 if (Result)
2833 RequestPacket->StatusBlock->Status = NO_ERROR;
2834 else
2835 RequestPacket->StatusBlock->Information = 0;
2836
2837// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
2838
2839 return TRUE;
2840}
2841
2842/**
2843 * VBoxVideoReset HW
2844 *
2845 * Resets the video hardware.
2846 */
2847BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
2848{
2849 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
2850
2851 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2852
2853 if (pDevExt->iDevice > 0)
2854 {
2855 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
2856 pDevExt->iDevice));
2857 return TRUE;
2858 }
2859
2860 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2861 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2862
2863 if (pDevExt->u.primary.pvReqFlush != NULL)
2864 {
2865 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
2866 pDevExt->u.primary.pvReqFlush = NULL;
2867 }
2868
2869 VbglTerminate ();
2870
2871 VBoxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvMiniportHeap, pDevExt->u.primary.cbMiniportHeap);
2872 VBoxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvAdapterInformation, VBVA_ADAPTER_INFORMATION_SIZE);
2873
2874 return TRUE;
2875}
2876
2877/**
2878 * VBoxVideoGetPowerState
2879 *
2880 * Queries whether the device can support the requested power state.
2881 */
2882VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2883 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2884{
2885 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
2886 return NO_ERROR;
2887}
2888
2889/**
2890 * VBoxVideoSetPowerState
2891 *
2892 * Sets the power state of the specified device
2893 */
2894VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2895 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2896{
2897 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
2898 return NO_ERROR;
2899}
2900#endif /* #ifndef VBOXWDDM */
2901
2902/**
2903 * VBoxVideoSetGraphicsCap
2904 *
2905 * Tells the host whether or not we currently support graphics in the
2906 * additions
2907 */
2908BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
2909{
2910 VMMDevReqGuestCapabilities2 *req = NULL;
2911 int rc;
2912
2913 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2914 sizeof (VMMDevReqGuestCapabilities2),
2915 VMMDevReq_SetGuestCapabilities);
2916
2917 if (!RT_SUCCESS(rc))
2918 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
2919 else
2920 {
2921 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
2922 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2923
2924 rc = VbglGRPerform (&req->header);
2925 if (RT_FAILURE(rc))
2926 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc\n", rc));
2927 }
2928 if (req != NULL)
2929 VbglGRFree (&req->header);
2930 return RT_SUCCESS(rc);
2931}
2932
2933
2934BOOLEAN FASTCALL VBoxVideoSetCurrentModePerform(PDEVICE_EXTENSION DeviceExtension,
2935 USHORT width, USHORT height, USHORT bpp
2936#ifdef VBOXWDDM
2937 , ULONG offDisplay
2938#endif
2939 )
2940{
2941 /* set the mode characteristics */
2942 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
2943 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, width);
2944 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
2945 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, height);
2946 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
2947 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, bpp);
2948 /* enable the mode */
2949 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2950 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
2951#ifdef VBOXWDDM
2952 /* encode linear offDisplay to xOffset & yOffset to ensure offset fits USHORT */
2953 ULONG cbLine = VBOXWDDM_ROUNDBOUND(((width * bpp) + 7) / 8, 4);
2954 ULONG xOffset = offDisplay % cbLine;
2955 ULONG yOffset = offDisplay / cbLine;
2956 Assert(xOffset <= 0xffff);
2957 Assert(yOffset <= 0xffff);
2958 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET);
2959 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)xOffset);
2960 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET);
2961 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)yOffset);
2962#endif
2963 /** @todo read from the port to see if the mode switch was successful */
2964
2965 /* Tell the host that we now support graphics in the additions.
2966 * @todo: Keep old behaviour, because VBoxVideoResetDevice is called on every graphics
2967 * mode switch and causes an OFF/ON sequence which is not handled by frontends
2968 * (for example Qt GUI debug build asserts when seamless is being enabled).
2969 */
2970 // VBoxVideoSetGraphicsCap(TRUE);
2971
2972 return TRUE;
2973}
2974
2975#ifndef VBOXWDDM
2976
2977/**
2978 * VBoxVideoSetCurrentMode
2979 *
2980 * Sets the adapter to the specified operating mode.
2981 */
2982BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2983 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
2984{
2985 PVIDEO_MODE_INFORMATION ModeInfo;
2986
2987 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
2988
2989 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
2990 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
2991 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
2992 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
2993
2994 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
2995 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
2996 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
2997
2998 if (DeviceExtension->iDevice > 0)
2999 {
3000 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
3001 DeviceExtension->iDevice));
3002 return TRUE;
3003 }
3004
3005 return VBoxVideoSetCurrentModePerform(DeviceExtension,
3006 (USHORT)ModeInfo->VisScreenWidth,
3007 (USHORT)ModeInfo->VisScreenHeight,
3008 (USHORT)ModeInfo->BitsPerPlane);
3009}
3010
3011/*
3012 * VBoxVideoResetDevice
3013 *
3014 * Resets the video hardware to the default mode, to which it was initialized
3015 * at system boot.
3016 */
3017
3018BOOLEAN FASTCALL VBoxVideoResetDevice(
3019 PDEVICE_EXTENSION DeviceExtension,
3020 PSTATUS_BLOCK StatusBlock)
3021{
3022 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
3023
3024 if (DeviceExtension->iDevice > 0)
3025 {
3026 /* If the device is the secondary display, however, it is recommended that no action be taken. */
3027 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
3028 DeviceExtension->iDevice));
3029 return TRUE;
3030 }
3031
3032#if 0
3033 /* Don't disable the extended video mode. This would only switch the video mode
3034 * to <current width> x <current height> x 0 bpp which is not what we want. And
3035 * even worse, it causes an disturbing additional mode switch */
3036 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
3037 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
3038#endif
3039
3040 /* Tell the host that we no longer support graphics in the additions
3041 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
3042 */
3043 // VBoxVideoSetGraphicsCap(FALSE);
3044 return TRUE;
3045}
3046
3047/**
3048 * VBoxVideoMapVideoMemory
3049 *
3050 * Maps the video hardware frame buffer and video RAM into the virtual address
3051 * space of the requestor.
3052 */
3053BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
3054 PVIDEO_MEMORY RequestedAddress,
3055 PVIDEO_MEMORY_INFORMATION MapInformation,
3056 PSTATUS_BLOCK StatusBlock)
3057{
3058 PHYSICAL_ADDRESS FrameBuffer;
3059 ULONG inIoSpace = 0;
3060 VP_STATUS Status;
3061
3062 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory: fb offset 0x%x\n", DeviceExtension->ulFrameBufferOffset));
3063
3064 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
3065
3066 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
3067#ifndef VBOX_WITH_HGSMI
3068 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize
3069 + DeviceExtension->pPrimary->u.primary.ulDisplayInformationSize;
3070#else
3071 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
3072#endif /* VBOX_WITH_HGSMI */
3073
3074 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
3075 &MapInformation->VideoRamLength, &inIoSpace,
3076 &MapInformation->VideoRamBase);
3077
3078 if (Status == NO_ERROR)
3079 {
3080 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
3081 MapInformation->FrameBufferLength =
3082 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
3083 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
3084 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
3085
3086 /* Save the new framebuffer size */
3087 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
3088#ifdef VBOX_WITH_HGSMI
3089 HGSMIAreaInitialize (&DeviceExtension->areaDisplay,
3090 MapInformation->FrameBufferBase,
3091 MapInformation->FrameBufferLength,
3092 DeviceExtension->ulFrameBufferOffset);
3093#endif /* VBOX_WITH_HGSMI */
3094 return TRUE;
3095 }
3096
3097 return FALSE;
3098}
3099
3100/**
3101 * VBoxVideoUnmapVideoMemory
3102 *
3103 * Releases a mapping between the virtual address space and the adapter's
3104 * frame buffer and video RAM.
3105 */
3106BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
3107 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
3108{
3109 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
3110#ifdef VBOX_WITH_HGSMI
3111 HGSMIAreaClear (&DeviceExtension->areaDisplay);
3112#endif /* VBOX_WITH_HGSMI */
3113 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
3114 return TRUE;
3115}
3116
3117/**
3118 * VBoxVideoQueryNumAvailModes
3119 *
3120 * Returns the number of video modes supported by the adapter and the size
3121 * in bytes of the video mode information, which can be used to allocate a
3122 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
3123 */
3124BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
3125 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
3126{
3127 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
3128 /* calculate the video modes table */
3129 VBoxBuildModesTable(DeviceExtension);
3130 Modes->NumModes = gNumVideoModes;
3131 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
3132 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
3133 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
3134 return TRUE;
3135}
3136
3137/**
3138 * VBoxVideoQueryAvailModes
3139 *
3140 * Returns information about each video mode supported by the adapter.
3141 */
3142BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
3143 PVIDEO_MODE_INFORMATION ReturnedModes,
3144 PSTATUS_BLOCK StatusBlock)
3145{
3146 ULONG Size;
3147
3148 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
3149
3150 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
3151 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
3152 StatusBlock->Information = Size;
3153
3154 return TRUE;
3155}
3156
3157/**
3158 * VBoxVideoQueryCurrentMode
3159 *
3160 * Returns information about current video mode.
3161 */
3162BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
3163 PVIDEO_MODE_INFORMATION VideoModeInfo,
3164 PSTATUS_BLOCK StatusBlock)
3165{
3166 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
3167
3168 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
3169 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
3170
3171 return TRUE;
3172}
3173#endif /* ifndef VBOXWDDM */
3174/*
3175 * VBoxVideoSetColorRegisters
3176 *
3177 * Sets the adapter's color registers to the specified RGB values. There
3178 * are code paths in this function, one generic and one for VGA compatible
3179 * controllers. The latter is needed for Bochs, where the generic one isn't
3180 * yet implemented.
3181 */
3182
3183BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
3184 PDEVICE_EXTENSION DeviceExtension,
3185 PVIDEO_CLUT ColorLookUpTable,
3186 PSTATUS_BLOCK StatusBlock)
3187{
3188 LONG Entry;
3189
3190 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
3191
3192 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
3193 return FALSE;
3194
3195 for (Entry = ColorLookUpTable->FirstEntry;
3196 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
3197 Entry++)
3198 {
3199 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c8, (UCHAR)Entry);
3200 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
3201 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
3202 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
3203 }
3204
3205 return TRUE;
3206}
3207
3208#ifndef VBOXWDDM
3209
3210VP_STATUS VBoxVideoGetChildDescriptor(
3211 PVOID HwDeviceExtension,
3212 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
3213 PVIDEO_CHILD_TYPE VideoChildType,
3214 PUCHAR pChildDescriptor,
3215 PULONG pUId,
3216 PULONG pUnused)
3217{
3218 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
3219 HwDeviceExtension, ChildEnumInfo));
3220
3221 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
3222
3223 if (ChildEnumInfo->ChildIndex > 0)
3224 {
3225 if ((int)ChildEnumInfo->ChildIndex <= pDevExt->pPrimary->u.primary.cDisplays)
3226 {
3227 *VideoChildType = Monitor;
3228 *pUId = ChildEnumInfo->ChildIndex;
3229
3230 return VIDEO_ENUM_MORE_DEVICES;
3231 }
3232 }
3233
3234 return ERROR_NO_MORE_DEVICES;
3235}
3236
3237
3238static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
3239{
3240 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
3241 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
3242
3243 if (pPrimaryDevExt)
3244 {
3245 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
3246
3247 if (req)
3248 {
3249 int rc = VbglGRPerform (&req->header);
3250
3251 if (RT_FAILURE(rc))
3252 {
3253 dprintf(("VBoxVideo::vbvaFlush: rc = %Rrc!\n", rc));
3254 }
3255 }
3256 }
3257
3258 return;
3259}
3260
3261int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
3262{
3263 int rc = VINF_SUCCESS;
3264
3265 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
3266
3267 /*
3268 * Query the VMMDev memory pointer. There we need VBVAMemory.
3269 */
3270 VMMDevMemory *pVMMDevMemory = NULL;
3271
3272 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
3273
3274 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
3275
3276 if (pDevExt->iDevice > 0)
3277 {
3278 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
3279
3280 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
3281 pDevExt->iDevice));
3282
3283 if ( ulEnable
3284 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
3285 {
3286 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
3287 pVbvaResult->pfnFlush = vboxVbvaFlush;
3288 pVbvaResult->pvFlush = pDevExt;
3289 }
3290 else
3291 {
3292 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
3293 }
3294
3295 return rc;
3296 }
3297
3298 if (RT_SUCCESS(rc))
3299 {
3300 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
3301 if (pDevExt->u.primary.pvReqFlush == NULL)
3302 {
3303 VMMDevVideoAccelFlush *req = NULL;
3304
3305 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
3306 sizeof (VMMDevVideoAccelFlush),
3307 VMMDevReq_VideoAccelFlush);
3308
3309 if (RT_SUCCESS (rc))
3310 {
3311 pDevExt->u.primary.pvReqFlush = req;
3312 }
3313 else
3314 {
3315 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Rrc!!!\n", rc));
3316 }
3317 }
3318 }
3319 else
3320 {
3321 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Rrc!!!\n", rc));
3322 }
3323
3324 if (RT_SUCCESS(rc))
3325 {
3326 ULONG ulEnabled = 0;
3327
3328 /*
3329 * Tell host that VBVA status is changed.
3330 */
3331 VMMDevVideoAccelEnable *req = NULL;
3332
3333 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
3334 sizeof (VMMDevVideoAccelEnable),
3335 VMMDevReq_VideoAccelEnable);
3336
3337 if (RT_SUCCESS(rc))
3338 {
3339 req->u32Enable = ulEnable;
3340 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
3341 req->fu32Status = 0;
3342
3343 rc = VbglGRPerform (&req->header);
3344
3345 if (RT_SUCCESS(rc))
3346 {
3347 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
3348 {
3349 /*
3350 * Initialize the result information and VBVA memory.
3351 */
3352 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
3353 {
3354 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
3355 pVbvaResult->pfnFlush = vboxVbvaFlush;
3356 pVbvaResult->pvFlush = pDevExt;
3357 ulEnabled = 1;
3358 }
3359 else
3360 {
3361 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
3362 }
3363
3364 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
3365 }
3366 else
3367 {
3368 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
3369
3370 /* Disable VBVA for old hosts. */
3371 req->u32Enable = 0;
3372 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
3373 req->fu32Status = 0;
3374
3375 VbglGRPerform (&req->header);
3376
3377 rc = VERR_NOT_SUPPORTED;
3378 }
3379 }
3380 else
3381 {
3382 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Rrc!\n", rc));
3383 }
3384
3385 VbglGRFree (&req->header);
3386 }
3387 else
3388 {
3389 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Rrc!\n", rc));
3390 }
3391
3392 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
3393 }
3394
3395 return rc;
3396}
3397#endif
Note: See TracBrowser for help on using the repository browser.

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