VirtualBox

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

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

wddm: StartDevice impl

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

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