VirtualBox

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

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

wddm: bugfix

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