VirtualBox

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

Last change on this file since 27165 was 27165, checked in by vboxsync, 15 years ago

Windows guest additions multimonitor fixes (xTracker 4655).

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