VirtualBox

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

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

burn fix

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

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