VirtualBox

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

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

wddm: initial stub prototype, make common XPDM-WDDM driver parts DM-agnostic

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 109.0 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 VideoRamBase = MmMapIoSpace(FrameBuffer,
957 VideoRamLength,
958 MmNonCached);
959 Status = VideoRamBase ? NO_ERROR : ERROR_INVALID_PARAMETER; /*<- this is what VideoPortMapMemory returns according to the docs */
960#endif
961
962 if (Status == NO_ERROR)
963 {
964 *ppv = VideoRamBase;
965 }
966
967 dprintf(("VBoxVideo::VBoxMapAdapterMemory rc = %d\n", Status));
968
969 return Status;
970}
971
972void VBoxUnmapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv, ULONG ulSize)
973{
974 dprintf(("VBoxVideo::VBoxMapAdapterMemory\n"));
975
976 if (*ppv)
977 {
978#ifndef VBOXWDDM
979 VideoPortUnmapMemory(PrimaryExtension, *ppv, NULL);
980#else
981 MmUnmapIoSpace(*ppv, ulSize);
982#endif
983 }
984
985 *ppv = NULL;
986}
987
988#ifndef VBOX_WITH_HGSMI
989
990# ifdef VBOXWDDM
991/* sanity check */
992# error WDDM is supported only for HGSMI-based driver
993# endif
994
995static void vboxQueryConf (PDEVICE_EXTENSION PrimaryExtension, uint32_t u32Index, ULONG *pulValue)
996{
997 dprintf(("VBoxVideo::vboxQueryConf: u32Index = %d\n", u32Index));
998
999 typedef struct _VBOXVIDEOQCONF32
1000 {
1001 VBOXVIDEOINFOHDR hdrQuery;
1002 VBOXVIDEOINFOQUERYCONF32 query;
1003 VBOXVIDEOINFOHDR hdrEnd;
1004 } VBOXVIDEOQCONF32;
1005
1006 VBOXVIDEOQCONF32 *p = (VBOXVIDEOQCONF32 *)PrimaryExtension->u.primary.pvAdapterInformation;
1007
1008 p->hdrQuery.u8Type = VBOX_VIDEO_INFO_TYPE_QUERY_CONF32;
1009 p->hdrQuery.u8Reserved = 0;
1010 p->hdrQuery.u16Length = sizeof (VBOXVIDEOINFOQUERYCONF32);
1011
1012 p->query.u32Index = u32Index;
1013 p->query.u32Value = 0;
1014
1015 p->hdrEnd.u8Type = VBOX_VIDEO_INFO_TYPE_END;
1016 p->hdrEnd.u8Reserved = 0;
1017 p->hdrEnd.u16Length = 0;
1018
1019 /* Let the host to process the commands. */
1020 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1021 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY);
1022
1023 *pulValue = (ULONG)p->query.u32Value;
1024
1025 dprintf(("VBoxVideo::vboxQueryConf: u32Value = %d\n", p->query.u32Value));
1026}
1027
1028static void vboxSetupAdapterInfo (PDEVICE_EXTENSION PrimaryExtension)
1029{
1030 dprintf(("VBoxVideo::vboxSetupAdapterInfo\n"));
1031
1032 VBOXVIDEOINFOHDR *pHdr;
1033
1034 uint8_t *pu8 = (uint8_t *)PrimaryExtension->u.primary.pvAdapterInformation;
1035
1036 PDEVICE_EXTENSION Extension = PrimaryExtension;
1037 while (Extension)
1038 {
1039 pHdr = (VBOXVIDEOINFOHDR *)pu8;
1040 pu8 += sizeof (VBOXVIDEOINFOHDR);
1041
1042 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_DISPLAY;
1043 pHdr->u8Reserved = 0;
1044 pHdr->u16Length = sizeof (VBOXVIDEOINFODISPLAY);
1045
1046 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8;
1047 pu8 += sizeof (VBOXVIDEOINFODISPLAY);
1048
1049 pDisplay->u32Index = Extension->iDevice;
1050 pDisplay->u32Offset = Extension->ulFrameBufferOffset;
1051 pDisplay->u32FramebufferSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
1052 pDisplay->u32InformationSize = PrimaryExtension->u.primary.ulDisplayInformationSize;
1053
1054 Extension = Extension->pNext;
1055 }
1056
1057
1058 /* The heap description. */
1059 pHdr = (VBOXVIDEOINFOHDR *)pu8;
1060 pu8 += sizeof (VBOXVIDEOINFOHDR);
1061
1062 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_NV_HEAP;
1063 pHdr->u8Reserved = 0;
1064 pHdr->u16Length = sizeof (VBOXVIDEOINFONVHEAP);
1065
1066 VBOXVIDEOINFONVHEAP *pHeap = (VBOXVIDEOINFONVHEAP *)pu8;
1067 pu8 += sizeof (VBOXVIDEOINFONVHEAP);
1068
1069 pHeap->u32HeapOffset = PrimaryExtension->u.primary.cbVRAM
1070 - PrimaryExtension->u.primary.cbMiniportHeap
1071 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
1072 pHeap->u32HeapSize = PrimaryExtension->u.primary.cbMiniportHeap;
1073
1074
1075 /* The END marker. */
1076 pHdr = (VBOXVIDEOINFOHDR *)pu8;
1077 pu8 += sizeof (VBOXVIDEOINFOHDR);
1078
1079 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_END;
1080 pHdr->u8Reserved = 0;
1081 pHdr->u16Length = 0;
1082
1083 /* Inform the host about the display configuration. */
1084 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1085 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY);
1086
1087 dprintf(("VBoxVideo::vboxSetupAdapterInfo finished\n"));
1088}
1089
1090/**
1091 * Helper function to register secondary displays (DualView). Note that this will not
1092 * be available on pre-XP versions, and some editions on XP will fail because they are
1093 * intentionally crippled.
1094 */
1095VOID VBoxSetupDisplays(PDEVICE_EXTENSION PrimaryExtension, PVIDEO_PORT_CONFIG_INFO pConfigInfo, ULONG AdapterMemorySize)
1096{
1097 VP_STATUS rc = NO_ERROR;
1098
1099 dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
1100 PrimaryExtension));
1101
1102 /* Preinitialize the primary extension. */
1103 PrimaryExtension->pNext = NULL;
1104 PrimaryExtension->pPrimary = PrimaryExtension;
1105 PrimaryExtension->iDevice = 0;
1106 PrimaryExtension->ulFrameBufferOffset = 0;
1107 PrimaryExtension->ulFrameBufferSize = 0;
1108 PrimaryExtension->u.primary.ulVbvaEnabled = 0;
1109 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1110 PrimaryExtension->u.primary.cDisplays = 1;
1111 PrimaryExtension->u.primary.cbVRAM = AdapterMemorySize;
1112 PrimaryExtension->u.primary.cbMiniportHeap = 0;
1113 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
1114 PrimaryExtension->u.primary.pvAdapterInformation = NULL;
1115 PrimaryExtension->u.primary.ulMaxFrameBufferSize = 0;
1116 PrimaryExtension->u.primary.ulDisplayInformationSize = 0;
1117
1118 /* Verify whether the HW supports VirtualBox extensions. */
1119 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1120 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_VBOX_VIDEO);
1121
1122 if (VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA) == VBE_DISPI_ID_VBOX_VIDEO)
1123 {
1124 PrimaryExtension->u.primary.bVBoxVideoSupported = TRUE;
1125 }
1126
1127 dprintf(("VBoxVideo::VBoxSetupDisplays: bVBoxVideoSupported = %d\n",
1128 PrimaryExtension->u.primary.bVBoxVideoSupported));
1129
1130 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1131 {
1132 /* Map the adapter information. It will be needed to query some configuration values. */
1133 rc = VBoxMapAdapterMemory (PrimaryExtension,
1134 &PrimaryExtension->u.primary.pvAdapterInformation,
1135 PrimaryExtension->u.primary.cbVRAM - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE,
1136 VBOX_VIDEO_ADAPTER_INFORMATION_SIZE
1137 );
1138 if (rc != NO_ERROR)
1139 {
1140 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
1141 rc));
1142
1143 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1144 }
1145 }
1146
1147 /* Setup the non-volatile heap and the adapter memory. */
1148 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1149 {
1150 /* Query the size of the non-volatile heap. */
1151 ULONG cbMiniportHeap = 0;
1152 vboxQueryConf (PrimaryExtension, VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE, &cbMiniportHeap);
1153
1154 /* Do not allow too big heap. 50% of VRAM should be enough. */
1155 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 2 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
1156
1157 if (cbMiniportHeap > cbMiniportHeapMaxSize)
1158 {
1159 cbMiniportHeap = cbMiniportHeapMaxSize;
1160 }
1161
1162 /* Round up to 4096. */
1163 PrimaryExtension->u.primary.cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
1164
1165 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
1166 cbMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap, cbMiniportHeapMaxSize));
1167
1168 /* Map the heap region and the adapter information area.
1169 *
1170 * Note: the heap will be used by display drivers, possibly by a few instances
1171 * in multimonitor configuration, but the memory is mapped here ones.
1172 * It is assumed that all display drivers and the miniport has the SAME
1173 * virtual address space.
1174 *
1175 */
1176 rc = VBoxMapAdapterMemory (PrimaryExtension,
1177 &PrimaryExtension->u.primary.pvMiniportHeap,
1178 PrimaryExtension->u.primary.cbVRAM
1179 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE
1180 - PrimaryExtension->u.primary.cbMiniportHeap,
1181 PrimaryExtension->u.primary.cbMiniportHeap
1182 );
1183
1184 if (rc != NO_ERROR)
1185 {
1186 PrimaryExtension->u.primary.cbMiniportHeap = 0;
1187 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1188 }
1189 }
1190
1191 /* Check whether the guest supports multimonitors. */
1192 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1193 {
1194 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
1195 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
1196
1197 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
1198 if (vboxQueryWinVersion() > WINNT4)
1199 {
1200 /* This bluescreens on NT4, hence the above version check */
1201 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
1202 (PrimaryExtension,
1203 (PUCHAR)"VideoPortCreateSecondaryDisplay");
1204 }
1205
1206 if (pfnCreateSecondaryDisplay != NULL)
1207 {
1208 /* Query the configured number of displays. */
1209 ULONG cDisplays = 0;
1210 vboxQueryConf (PrimaryExtension, VBOX_VIDEO_QCI32_MONITOR_COUNT, &cDisplays);
1211
1212 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
1213 cDisplays));
1214
1215 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
1216 {
1217 /* Host reported some bad value. Continue in the 1 screen mode. */
1218 cDisplays = 1;
1219 }
1220
1221 PDEVICE_EXTENSION pPrev = PrimaryExtension;
1222
1223 ULONG iDisplay;
1224 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
1225 {
1226 PDEVICE_EXTENSION SecondaryExtension = NULL;
1227 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
1228
1229 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
1230 rc, SecondaryExtension));
1231
1232 if (rc != NO_ERROR)
1233 {
1234 break;
1235 }
1236
1237 SecondaryExtension->pNext = NULL;
1238 SecondaryExtension->pPrimary = PrimaryExtension;
1239 SecondaryExtension->iDevice = iDisplay;
1240 SecondaryExtension->ulFrameBufferOffset = 0;
1241 SecondaryExtension->ulFrameBufferSize = 0;
1242 SecondaryExtension->u.secondary.bEnabled = FALSE;
1243
1244 /* Update the list pointers. */
1245 pPrev->pNext = SecondaryExtension;
1246 pPrev = SecondaryExtension;
1247
1248 /* Take the successfully created display into account. */
1249 PrimaryExtension->u.primary.cDisplays++;
1250 }
1251
1252 /* Failure to create secondary displays is not fatal */
1253 rc = NO_ERROR;
1254 }
1255 }
1256
1257 /* Now when the number of monitors is known and extensions are created,
1258 * calculate the layout of framebuffers.
1259 */
1260 VBoxComputeFrameBufferSizes (PrimaryExtension);
1261
1262 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1263 {
1264 /* Setup the information for the host. */
1265 vboxSetupAdapterInfo (PrimaryExtension);
1266 }
1267 else
1268 {
1269 /* Unmap the memory if VBoxVideo is not supported. */
1270 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap);
1271 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvAdapterInformation, VBOX_VIDEO_ADAPTER_INFORMATION_SIZE);
1272 }
1273
1274 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
1275}
1276#endif /* !VBOX_WITH_HGSMI */
1277
1278#ifndef VBOXWDDM
1279
1280VP_STATUS VBoxVideoFindAdapter(IN PVOID HwDeviceExtension,
1281 IN PVOID HwContext, IN PWSTR ArgumentString,
1282 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
1283 OUT PUCHAR Again)
1284{
1285 VP_STATUS rc;
1286 USHORT DispiId;
1287 ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
1288 VIDEO_ACCESS_RANGE AccessRanges[] =
1289 {
1290 {
1291 {0, VBE_DISPI_LFB_PHYSICAL_ADDRESS},
1292 VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES,
1293 0,
1294 FALSE,
1295 FALSE,
1296 0
1297 }
1298 };
1299
1300 dprintf(("VBoxVideo::VBoxVideoFindAdapter %p\n", HwDeviceExtension));
1301
1302#ifdef VBOX_WITH_HGSMI
1303 VBoxSetupVideoPortFunctions((PDEVICE_EXTENSION)HwDeviceExtension, &((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.VideoPortProcs, ConfigInfo);
1304#endif
1305
1306 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1307 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
1308 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
1309 if (DispiId == VBE_DISPI_ID2)
1310 {
1311 dprintf(("VBoxVideo::VBoxVideoFoundAdapter: found the VBE card\n"));
1312 /*
1313 * Write some hardware information to registry, so that
1314 * it's visible in Windows property dialog.
1315 */
1316
1317 rc = VideoPortSetRegistryParameters(
1318 HwDeviceExtension,
1319 L"HardwareInformation.ChipType",
1320 VBoxChipType,
1321 sizeof(VBoxChipType));
1322
1323 rc = VideoPortSetRegistryParameters(
1324 HwDeviceExtension,
1325 L"HardwareInformation.DacType",
1326 VBoxDACType,
1327 sizeof(VBoxDACType));
1328
1329 /*
1330 * Query the adapter's memory size. It's a bit of a hack, we just read
1331 * an ULONG from the data port without setting an index before.
1332 */
1333 AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
1334 rc = VideoPortSetRegistryParameters(
1335 HwDeviceExtension,
1336 L"HardwareInformation.MemorySize",
1337 &AdapterMemorySize,
1338 sizeof(ULONG));
1339
1340 rc = VideoPortSetRegistryParameters(
1341 HwDeviceExtension,
1342 L"HardwareInformation.AdapterString",
1343 VBoxAdapterString,
1344 sizeof(VBoxAdapterString));
1345
1346 rc = VideoPortSetRegistryParameters(
1347 HwDeviceExtension,
1348 L"HardwareInformation.BiosString",
1349 VBoxBiosString,
1350 sizeof(VBoxBiosString));
1351#ifdef VBOX_WITH_HGSMI
1352 if (VBoxHGSMIIsSupported ((PDEVICE_EXTENSION)HwDeviceExtension))
1353 {
1354 dprintf(("VBoxVideo::VBoxVideoFindAdapter: calling VideoPortGetAccessRanges\n"));
1355
1356 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.IOPortHost = (RTIOPORT)VGA_PORT_HGSMI_HOST;
1357 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.IOPortGuest = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
1358
1359 VIDEO_ACCESS_RANGE tmpRanges[4];
1360 ULONG slot = 0;
1361
1362 VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));
1363
1364 /* need to call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up */
1365 VP_STATUS status;
1366 if (vboxQueryWinVersion() == WINNT4)
1367 {
1368 /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
1369 * and needs PCI ids for a successful VideoPortGetAccessRanges call.
1370 */
1371 ULONG vendorId = 0x80EE;
1372 ULONG deviceId = 0xBEEF;
1373 status = VideoPortGetAccessRanges(HwDeviceExtension,
1374 0,
1375 NULL,
1376 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1377 tmpRanges,
1378 &vendorId,
1379 &deviceId,
1380 &slot);
1381 }
1382 else
1383 {
1384 status = VideoPortGetAccessRanges(HwDeviceExtension,
1385 0,
1386 NULL,
1387 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1388 tmpRanges,
1389 NULL,
1390 NULL,
1391 &slot);
1392 }
1393 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortGetAccessRanges status 0x%x\n", status));
1394
1395 /* no matter what we get with VideoPortGetAccessRanges, we assert the default ranges */
1396 }
1397#endif /* VBOX_WITH_HGSMI */
1398 rc = VideoPortVerifyAccessRanges(HwDeviceExtension, 1, AccessRanges);
1399 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortVerifyAccessRanges returned 0x%x\n", rc));
1400 // @todo for some reason, I get an ERROR_INVALID_PARAMETER from NT4 SP0
1401 // It does not seem to like getting me these port addresses. So I just
1402 // pretend success to make the driver work.
1403 rc = NO_ERROR;
1404
1405#ifndef VBOX_WITH_HGSMI
1406 /* Initialize VBoxGuest library */
1407 rc = VbglInit ();
1408
1409 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
1410
1411 /* Setup the Device Extension and if possible secondary displays. */
1412 VBoxSetupDisplays((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
1413#else
1414 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
1415 rc = VbglInit ();
1416
1417 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
1418 * code will be ifdef'ed and later removed.
1419 * The host will however support both old and new interface to keep compatibility
1420 * with old guest additions.
1421 */
1422 VBoxSetupDisplaysHGSMI((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
1423
1424 if (((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.bHGSMI)
1425 {
1426 LogRel(("VBoxVideo: using HGSMI\n"));
1427 }
1428#endif /* VBOX_WITH_HGSMI */
1429
1430 // pretend success to make the driver work.
1431 rc = NO_ERROR;
1432 } else
1433 {
1434 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
1435 rc = ERROR_DEV_NOT_EXIST;
1436 }
1437 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
1438 return rc;
1439}
1440
1441/**
1442 * VBoxVideoInitialize
1443 *
1444 * Performs the first initialization of the adapter, after the HAL has given
1445 * up control of the video hardware to the video port driver.
1446 */
1447BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
1448{
1449 VP_STATUS status;
1450
1451 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
1452
1453 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1454
1455 /* Initialize the request pointer. */
1456 pDevExt->u.primary.pvReqFlush = NULL;
1457
1458 /*
1459 * Get the last custom resolution
1460 */
1461 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1462 L"CustomXRes",
1463 FALSE,
1464 VBoxRegistryCallback,
1465 &gCustomXRes);
1466 if (status != NO_ERROR)
1467 gCustomXRes = 0;
1468 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1469 L"CustomYRes",
1470 FALSE,
1471 VBoxRegistryCallback,
1472 &gCustomYRes);
1473 if (status != NO_ERROR)
1474 gCustomYRes = 0;
1475 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1476 L"CustomBPP",
1477 FALSE,
1478 VBoxRegistryCallback,
1479 &gCustomBPP);
1480 if (status != NO_ERROR)
1481 gCustomBPP = 0;
1482
1483 dprintf(("VBoxVideo: got stored custom resolution %dx%dx%d\n", gCustomXRes, gCustomYRes, gCustomBPP));
1484 return TRUE;
1485}
1486
1487# if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL)
1488
1489BOOLEAN VBoxVideoInterrupt(PVOID HwDeviceExtension)
1490{
1491 PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1492 PDEVICE_EXTENSION PrimaryExtension = devExt->pPrimary;
1493 if (PrimaryExtension)
1494 {
1495 if (PrimaryExtension->u.primary.pHostFlags) /* If HGSMI is enabled at all. */
1496 {
1497 uint32_t flags = PrimaryExtension->u.primary.pHostFlags->u32HostFlags;
1498 if((flags & HGSMIHOSTFLAGS_IRQ) != 0)
1499 {
1500 if((flags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0)
1501 {
1502 /* schedule a DPC*/
1503 BOOLEAN bResult = PrimaryExtension->u.primary.VideoPortProcs.pfnQueueDpc(PrimaryExtension, VBoxVideoHGSMIDpc, (PVOID)1);
1504 Assert(bResult);
1505 }
1506 /* clear the IRQ */
1507 HGSMIClearIrq (PrimaryExtension);
1508 return TRUE;
1509 }
1510 }
1511 }
1512 return FALSE;
1513}
1514# endif /* #if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL) */
1515#endif /* #ifndef VBOXWDDM */
1516/**
1517 * Send a request to the host to make the absolute pointer visible
1518 */
1519static BOOLEAN ShowPointer(PVOID HwDeviceExtension)
1520{
1521 BOOLEAN Result = TRUE;
1522
1523 if (DEV_MOUSE_HIDDEN((PDEVICE_EXTENSION)HwDeviceExtension))
1524 {
1525 // tell the host to use the guest's pointer
1526 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1527
1528 /* Visible and No Shape means Show the pointer.
1529 * It is enough to init only this field.
1530 */
1531 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
1532
1533#ifndef VBOX_WITH_HGSMI
1534 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
1535#else
1536 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, &PointerAttributes, sizeof (PointerAttributes));
1537#endif /* VBOX_WITH_HGSMI */
1538
1539 if (Result)
1540 DEV_SET_MOUSE_SHOWN((PDEVICE_EXTENSION)HwDeviceExtension);
1541 else
1542 dprintf(("VBoxVideo::ShowPointer: Could not show the hardware pointer -> fallback\n"));
1543 }
1544 return Result;
1545}
1546
1547#ifndef VBOXWDDM
1548/**
1549 * VBoxVideoStartIO
1550 *
1551 * Processes the specified Video Request Packet.
1552 */
1553BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
1554 PVIDEO_REQUEST_PACKET RequestPacket)
1555{
1556 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1557
1558 BOOLEAN Result;
1559
1560// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
1561
1562 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1563
1564 switch (RequestPacket->IoControlCode)
1565 {
1566 case IOCTL_VIDEO_SET_CURRENT_MODE:
1567 {
1568 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
1569 {
1570 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1571 return TRUE;
1572 }
1573 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1574 (PVIDEO_MODE)RequestPacket->InputBuffer,
1575 RequestPacket->StatusBlock);
1576 break;
1577 }
1578
1579 case IOCTL_VIDEO_RESET_DEVICE:
1580 {
1581 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
1582 RequestPacket->StatusBlock);
1583 break;
1584 }
1585
1586 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
1587 {
1588 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
1589 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1590 {
1591 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1592 return TRUE;
1593 }
1594 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1595 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1596 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
1597 RequestPacket->StatusBlock);
1598 break;
1599 }
1600
1601 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
1602 {
1603 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1604 {
1605 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1606 return TRUE;
1607 }
1608 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1609 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1610 RequestPacket->StatusBlock);
1611 break;
1612 }
1613
1614 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
1615 {
1616 PVIDEO_SHARE_MEMORY pShareMemory;
1617 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
1618 PHYSICAL_ADDRESS shareAddress;
1619 PVOID virtualAddress = NULL;
1620 ULONG sharedViewSize;
1621 ULONG inIoSpace = 0;
1622 VP_STATUS status;
1623
1624 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
1625
1626 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
1627 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
1628
1629 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1630 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1631 Result = FALSE;
1632 break;
1633 }
1634
1635 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1636
1637 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
1638 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
1639
1640 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));
1641 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
1642 Result = FALSE;
1643 break;
1644 }
1645
1646 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
1647
1648 virtualAddress = pShareMemory->ProcessHandle;
1649 sharedViewSize = pShareMemory->ViewSize;
1650
1651 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
1652
1653 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
1654 if (status != NO_ERROR)
1655 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
1656 Result = (status == NO_ERROR);
1657
1658 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
1659 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
1660 pShareMemoryInformation->VirtualAddress = virtualAddress;
1661 pShareMemoryInformation->SharedViewSize = sharedViewSize;
1662 break;
1663 }
1664
1665 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
1666 {
1667 PVIDEO_SHARE_MEMORY pShareMemory;
1668 VP_STATUS status;
1669
1670 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
1671
1672 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
1673 {
1674 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1675 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1676 Result = FALSE;
1677 break;
1678 }
1679
1680 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1681
1682 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
1683 if (status != NO_ERROR)
1684 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
1685 Result = (status == NO_ERROR);
1686 break;
1687 }
1688
1689 /*
1690 * The display driver asks us how many video modes we support
1691 * so that it can supply an appropriate buffer for the next call.
1692 */
1693 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
1694 {
1695 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
1696 {
1697 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1698 return TRUE;
1699 }
1700 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1701 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
1702 RequestPacket->StatusBlock);
1703 break;
1704 }
1705
1706 /*
1707 * The display driver asks us to provide a list of supported video modes
1708 * into a buffer it has allocated.
1709 */
1710 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
1711 {
1712 if (RequestPacket->OutputBufferLength <
1713 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
1714 {
1715 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1716 return TRUE;
1717 }
1718 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1719 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1720 RequestPacket->StatusBlock);
1721 break;
1722 }
1723
1724 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
1725 {
1726 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
1727 RequestPacket->InputBufferLength <
1728 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
1729 sizeof(VIDEO_CLUT))
1730 {
1731 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1732 return TRUE;
1733 }
1734 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
1735 (PVIDEO_CLUT)RequestPacket->InputBuffer,
1736 RequestPacket->StatusBlock);
1737 break;
1738 }
1739
1740 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
1741 {
1742 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
1743 {
1744 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1745 return TRUE;
1746 }
1747 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1748 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1749 RequestPacket->StatusBlock);
1750 break;
1751 }
1752
1753 // show the pointer
1754 case IOCTL_VIDEO_ENABLE_POINTER:
1755 {
1756 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
1757 // find out whether the host wants absolute positioning
1758 /// @todo this is now obsolete - remove it?
1759 if (vboxQueryHostWantsAbsolute())
1760 Result = ShowPointer(HwDeviceExtension);
1761 else
1762 {
1763 // fallback to software pointer
1764 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1765 Result = FALSE;
1766 }
1767 break;
1768 }
1769
1770 // hide the pointer
1771 case IOCTL_VIDEO_DISABLE_POINTER:
1772 {
1773 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
1774 // find out whether the host wants absolute positioning
1775 if (vboxQueryHostWantsAbsolute())
1776 {
1777 // tell the host to hide pointer
1778 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1779
1780 /* Enable == 0 means no shape, not visible.
1781 * It is enough to init only this field.
1782 */
1783 PointerAttributes.Enable = 0;
1784
1785#ifndef VBOX_WITH_HGSMI
1786 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
1787#else
1788 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, &PointerAttributes, sizeof (PointerAttributes));
1789#endif /* VBOX_WITH_HGSMI */
1790
1791 if (Result)
1792 DEV_SET_MOUSE_HIDDEN((PDEVICE_EXTENSION)HwDeviceExtension);
1793 else
1794 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
1795 } else
1796 {
1797 // fallback to software pointer
1798 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1799 Result = FALSE;
1800 }
1801 break;
1802 }
1803
1804 /*
1805 * Change the pointer shape
1806 */
1807 case IOCTL_VIDEO_SET_POINTER_ATTR:
1808 {
1809 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
1810 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
1811 {
1812 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
1813 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1814 return TRUE;
1815 }
1816 // find out whether the host wants absolute positioning
1817 if (vboxQueryHostWantsAbsolute())
1818 {
1819 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
1820#if 0
1821 dprintf(("Pointer shape information:\n"
1822 "\tFlags: %d\n"
1823 "\tWidth: %d\n"
1824 "\tHeight: %d\n"
1825 "\tWidthInBytes: %d\n"
1826 "\tEnable: %d\n"
1827 "\tColumn: %d\n"
1828 "\tRow: %d\n",
1829 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
1830 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
1831 pPointerAttributes->Row));
1832 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
1833#endif
1834#ifndef VBOX_WITH_HGSMI
1835 Result = vboxUpdatePointerShape(pPointerAttributes, RequestPacket->InputBufferLength);
1836#else
1837 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, pPointerAttributes, RequestPacket->InputBufferLength);
1838#endif /* VBOX_WITH_HGSMI */
1839 if (!Result)
1840 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
1841 } else
1842 {
1843 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
1844 // fallback to software pointer
1845 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1846 Result = FALSE;
1847 }
1848 break;
1849 }
1850
1851 // query pointer information
1852 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
1853 {
1854 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
1855 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1856 Result = FALSE;
1857 break;
1858 }
1859
1860 // set the pointer position
1861 case IOCTL_VIDEO_SET_POINTER_POSITION:
1862 {
1863 // find out whether the host wants absolute positioning
1864 /// @todo this is now obsolete - remove it?
1865 if (vboxQueryHostWantsAbsolute())
1866 Result = ShowPointer(HwDeviceExtension);
1867 else
1868 {
1869 // fallback to software pointer
1870 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1871 Result = FALSE;
1872 }
1873 break;
1874 }
1875
1876 // query the pointer position
1877 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
1878 {
1879 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
1880 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
1881 {
1882 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
1883 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1884 return TRUE;
1885 }
1886 Result = FALSE;
1887 uint16_t mousePosX;
1888 uint16_t mousePosY;
1889 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
1890 {
1891 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
1892 PVIDEO_MODE_INFORMATION ModeInfo;
1893 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
1894 // map from 0xFFFF to the current resolution
1895 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
1896 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
1897 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
1898 Result = TRUE;
1899 }
1900 if (!Result)
1901 {
1902 // fallback to software pointer
1903 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1904 }
1905 break;
1906 }
1907
1908 // Determine hardware cursor capabilities. We will always report that we are
1909 // very capable even though the host might not want to do pointer integration.
1910 // This is done because we can still return errors on the actual calls later to
1911 // make the display driver go to the fallback routines.
1912 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
1913 {
1914 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
1915 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
1916 {
1917 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
1918 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1919 return TRUE;
1920 }
1921 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
1922 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
1923 VIDEO_MODE_COLOR_POINTER |
1924 VIDEO_MODE_MONO_POINTER;
1925 // for now we go with 64x64 cursors
1926 pCaps->MaxWidth = 64;
1927 pCaps->MaxHeight = 64;
1928 // that doesn't seem to be relevant, VBoxDisp doesn't use it
1929 pCaps->HWPtrBitmapStart = -1;
1930 pCaps->HWPtrBitmapEnd = -1;
1931 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
1932 Result = TRUE;
1933 break;
1934 }
1935
1936 /* Attach/detach DualView devices */
1937 case IOCTL_VIDEO_SWITCH_DUALVIEW:
1938 {
1939 ULONG ulAttach;
1940
1941 ulAttach = *((PULONG)RequestPacket->InputBuffer);
1942 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
1943
1944 if (pDevExt->iDevice > 0)
1945 {
1946 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
1947 }
1948 Result = TRUE;
1949 break;
1950 }
1951
1952 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
1953 {
1954 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
1955
1956 if (pDevExt->pPrimary->u.primary.bVBoxVideoSupported)
1957 {
1958 /* The display driver must have prepared the monitor information. */
1959 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1960 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE + pDevExt->iDevice);
1961 }
1962 else
1963 {
1964 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1965 }
1966 Result = pDevExt->pPrimary->u.primary.bVBoxVideoSupported;
1967 break;
1968 }
1969
1970#ifndef VBOX_WITH_HGSMI
1971 case IOCTL_VIDEO_QUERY_DISPLAY_INFO:
1972 {
1973 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_DISPLAY_INFO\n"));
1974
1975 if (RequestPacket->OutputBufferLength < sizeof(QUERYDISPLAYINFORESULT))
1976 {
1977 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
1978 RequestPacket->OutputBufferLength, sizeof(QUERYDISPLAYINFORESULT)));
1979 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1980 return FALSE;
1981 }
1982
1983 QUERYDISPLAYINFORESULT *pDispInfo = (QUERYDISPLAYINFORESULT *)RequestPacket->OutputBuffer;
1984
1985 pDispInfo->iDevice = pDevExt->iDevice;
1986 pDispInfo->u32DisplayInfoSize = pDevExt->pPrimary->u.primary.ulDisplayInformationSize;
1987
1988 RequestPacket->StatusBlock->Information = sizeof(QUERYDISPLAYINFORESULT);
1989 Result = TRUE;
1990
1991 break;
1992 }
1993#endif /* !VBOX_WITH_HGSMI */
1994
1995 case IOCTL_VIDEO_VBVA_ENABLE:
1996 {
1997 int rc;
1998 ULONG ulEnable;
1999
2000 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
2001
2002 if (RequestPacket->InputBufferLength < sizeof(ULONG))
2003 {
2004 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
2005 RequestPacket->InputBufferLength, sizeof(ULONG)));
2006 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2007 return FALSE;
2008 }
2009
2010 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
2011 {
2012 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2013 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
2014 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2015 return FALSE;
2016 }
2017
2018 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
2019 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
2020
2021 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
2022 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Rrc\n", rc));
2023
2024 if (RT_FAILURE (rc))
2025 {
2026 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
2027 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2028 return FALSE;
2029 }
2030
2031 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
2032 Result = TRUE;
2033
2034 break;
2035 }
2036
2037 /* Private ioctls */
2038 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
2039 {
2040 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
2041 int rc;
2042
2043 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
2044 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
2045 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
2046 {
2047 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
2048 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
2049 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2050 return FALSE;
2051 }
2052 /*
2053 * Inform the host about the visible region
2054 */
2055 VMMDevVideoSetVisibleRegion *req = NULL;
2056
2057 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2058 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
2059 VMMDevReq_VideoSetVisibleRegion);
2060
2061 if (RT_SUCCESS(rc))
2062 {
2063 req->cRect = cRect;
2064 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
2065
2066 rc = VbglGRPerform (&req->header);
2067
2068 if (RT_SUCCESS(rc) && RT_SUCCESS(req->header.rc))
2069 {
2070 Result = TRUE;
2071 break;
2072 }
2073 }
2074 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x (hdr.rc=%x)\n", rc, (req) ? req->header.rc : -1));
2075 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2076 return FALSE;
2077 }
2078
2079#ifdef VBOX_WITH_HGSMI
2080 case IOCTL_VIDEO_QUERY_HGSMI_INFO:
2081 {
2082 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_HGSMI_INFO\n"));
2083
2084 if (RequestPacket->OutputBufferLength < sizeof(QUERYHGSMIRESULT))
2085 {
2086 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2087 RequestPacket->OutputBufferLength, sizeof(QUERYHGSMIRESULT)));
2088 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2089 return FALSE;
2090 }
2091
2092 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2093 {
2094 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2095 return FALSE;
2096 }
2097
2098 QUERYHGSMIRESULT *pInfo = (QUERYHGSMIRESULT *)RequestPacket->OutputBuffer;
2099
2100 pInfo->iDevice = pDevExt->iDevice;
2101 pInfo->ulFlags = 0;
2102
2103 /* Describes VRAM chunk for this display device. */
2104 pInfo->areaDisplay = pDevExt->areaDisplay;
2105
2106 pInfo->u32DisplayInfoSize = VBVA_DISPLAY_INFORMATION_SIZE;
2107 pInfo->u32MinVBVABufferSize = VBVA_MIN_BUFFER_SIZE;
2108
2109 pInfo->IOPortGuestCommand = pDevExt->pPrimary->u.primary.IOPortGuest;
2110
2111 RequestPacket->StatusBlock->Information = sizeof(QUERYHGSMIRESULT);
2112 Result = TRUE;
2113
2114 break;
2115 }
2116 case IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS:
2117 {
2118 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS\n"));
2119
2120 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCALLBACKS))
2121 {
2122 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2123 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCALLBACKS)));
2124 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2125 return FALSE;
2126 }
2127
2128 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2129 {
2130 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2131 return FALSE;
2132 }
2133
2134 HGSMIQUERYCALLBACKS *pInfo = (HGSMIQUERYCALLBACKS *)RequestPacket->OutputBuffer;
2135
2136 pInfo->hContext = pDevExt;
2137 pInfo->pfnCompletionHandler = hgsmiHostCmdComplete;
2138 pInfo->pfnRequestCommandsHandler = hgsmiHostCmdRequest;
2139
2140 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCALLBACKS);
2141 Result = TRUE;
2142 break;
2143 }
2144 case IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS:
2145 {
2146 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS\n"));
2147
2148 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCPORTPROCS))
2149 {
2150 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2151 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCPORTPROCS)));
2152 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2153 return FALSE;
2154 }
2155
2156 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2157 {
2158 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2159 return FALSE;
2160 }
2161
2162 HGSMIQUERYCPORTPROCS *pInfo = (HGSMIQUERYCPORTPROCS *)RequestPacket->OutputBuffer;
2163 pInfo->pContext = pDevExt->pPrimary;
2164 pInfo->VideoPortProcs = pDevExt->pPrimary->u.primary.VideoPortProcs;
2165
2166 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCPORTPROCS);
2167 Result = TRUE;
2168 break;
2169 }
2170 case IOCTL_VIDEO_HGSMI_HANDLER_ENABLE:
2171 {
2172 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_HANDLER_ENABLE\n"));
2173
2174 if (RequestPacket->InputBufferLength< sizeof(HGSMIHANDLERENABLE))
2175 {
2176 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2177 RequestPacket->InputBufferLength, sizeof(HGSMIHANDLERENABLE)));
2178 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2179 return FALSE;
2180 }
2181
2182 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2183 {
2184 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2185 return FALSE;
2186 }
2187
2188 HGSMIHANDLERENABLE *pInfo = (HGSMIHANDLERENABLE *)RequestPacket->InputBuffer;
2189
2190 int rc = vboxVBVAChannelDisplayEnable(pDevExt->pPrimary,
2191 pDevExt->iDevice,
2192 pInfo->u8Channel);
2193 if(RT_FAILURE(rc))
2194 {
2195 RequestPacket->StatusBlock->Status = ERROR_INVALID_NAME;
2196 }
2197 Result = TRUE;
2198 break;
2199 }
2200 case IOCTL_VIDEO_HGSMI_HANDLER_DISABLE:
2201 {
2202 /* TODO: implement */
2203 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2204 {
2205 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2206 return FALSE;
2207 }
2208 break;
2209 }
2210#endif /* VBOX_WITH_HGSMI */
2211
2212 default:
2213 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
2214 RequestPacket->IoControlCode,
2215 (RequestPacket->IoControlCode >> 2) & 0xFFF,
2216 (RequestPacket->IoControlCode >> 2) & 0xFFF));
2217 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2218 return FALSE;
2219 }
2220
2221 if (Result)
2222 RequestPacket->StatusBlock->Status = NO_ERROR;
2223 else
2224 RequestPacket->StatusBlock->Information = 0;
2225
2226// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
2227
2228 return TRUE;
2229}
2230
2231/**
2232 * VBoxVideoReset HW
2233 *
2234 * Resets the video hardware.
2235 */
2236BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
2237{
2238 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
2239
2240 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2241
2242 if (pDevExt->iDevice > 0)
2243 {
2244 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
2245 pDevExt->iDevice));
2246 return TRUE;
2247 }
2248
2249 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2250 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2251
2252 if (pDevExt->u.primary.pvReqFlush != NULL)
2253 {
2254 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
2255 pDevExt->u.primary.pvReqFlush = NULL;
2256 }
2257
2258 VbglTerminate ();
2259
2260 VBoxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvMiniportHeap, pDevExt->u.primary.cbMiniportHeap);
2261 VBoxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvAdapterInformation, VBVA_ADAPTER_INFORMATION_SIZE);
2262
2263 return TRUE;
2264}
2265
2266/**
2267 * VBoxVideoGetPowerState
2268 *
2269 * Queries whether the device can support the requested power state.
2270 */
2271VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2272 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2273{
2274 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
2275 return NO_ERROR;
2276}
2277
2278/**
2279 * VBoxVideoSetPowerState
2280 *
2281 * Sets the power state of the specified device
2282 */
2283VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2284 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2285{
2286 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
2287 return NO_ERROR;
2288}
2289#endif /* #ifndef VBOXWDDM */
2290
2291/**
2292 * VBoxVideoSetGraphicsCap
2293 *
2294 * Tells the host whether or not we currently support graphics in the
2295 * additions
2296 */
2297BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
2298{
2299 VMMDevReqGuestCapabilities2 *req = NULL;
2300 int rc;
2301
2302 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2303 sizeof (VMMDevReqGuestCapabilities2),
2304 VMMDevReq_SetGuestCapabilities);
2305
2306 if (!RT_SUCCESS(rc))
2307 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
2308 else
2309 {
2310 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
2311 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2312
2313 rc = VbglGRPerform (&req->header);
2314 if (!RT_SUCCESS(rc) || !RT_SUCCESS(req->header.rc))
2315 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc, VMMDev rc = %Rrc\n", rc, req->header.rc));
2316 if (RT_SUCCESS(rc))
2317 rc = req->header.rc;
2318 }
2319 if (req != NULL)
2320 VbglGRFree (&req->header);
2321 return RT_SUCCESS(rc);
2322}
2323
2324#ifndef VBOXWDDM
2325
2326/**
2327 * VBoxVideoSetCurrentMode
2328 *
2329 * Sets the adapter to the specified operating mode.
2330 */
2331BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2332 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
2333{
2334 PVIDEO_MODE_INFORMATION ModeInfo;
2335
2336 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
2337
2338 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
2339 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
2340 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
2341 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
2342
2343 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
2344 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
2345 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
2346
2347 if (DeviceExtension->iDevice > 0)
2348 {
2349 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
2350 DeviceExtension->iDevice));
2351 return TRUE;
2352 }
2353
2354 /* set the mode characteristics */
2355 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
2356 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenWidth);
2357 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
2358 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenHeight);
2359 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
2360 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->BitsPerPlane);
2361 /* enable the mode */
2362 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2363 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
2364 /** @todo read from the port to see if the mode switch was successful */
2365
2366 /* Tell the host that we now support graphics in the additions.
2367 * @todo: Keep old behaviour, because VBoxVideoResetDevice is called on every graphics
2368 * mode switch and causes an OFF/ON sequence which is not handled by frontends
2369 * (for example Qt GUI debug build asserts when seamless is being enabled).
2370 */
2371 // VBoxVideoSetGraphicsCap(TRUE);
2372 return TRUE;
2373}
2374
2375/*
2376 * VBoxVideoResetDevice
2377 *
2378 * Resets the video hardware to the default mode, to which it was initialized
2379 * at system boot.
2380 */
2381
2382BOOLEAN FASTCALL VBoxVideoResetDevice(
2383 PDEVICE_EXTENSION DeviceExtension,
2384 PSTATUS_BLOCK StatusBlock)
2385{
2386 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
2387
2388 if (DeviceExtension->iDevice > 0)
2389 {
2390 /* If the device is the secondary display, however, it is recommended that no action be taken. */
2391 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
2392 DeviceExtension->iDevice));
2393 return TRUE;
2394 }
2395
2396#if 0
2397 /* Don't disable the extended video mode. This would only switch the video mode
2398 * to <current width> x <current height> x 0 bpp which is not what we want. And
2399 * even worse, it causes an disturbing additional mode switch */
2400 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2401 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2402#endif
2403
2404 /* Tell the host that we no longer support graphics in the additions
2405 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
2406 */
2407 // VBoxVideoSetGraphicsCap(FALSE);
2408 return TRUE;
2409}
2410
2411/**
2412 * VBoxVideoMapVideoMemory
2413 *
2414 * Maps the video hardware frame buffer and video RAM into the virtual address
2415 * space of the requestor.
2416 */
2417BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2418 PVIDEO_MEMORY RequestedAddress,
2419 PVIDEO_MEMORY_INFORMATION MapInformation,
2420 PSTATUS_BLOCK StatusBlock)
2421{
2422 PHYSICAL_ADDRESS FrameBuffer;
2423 ULONG inIoSpace = 0;
2424 VP_STATUS Status;
2425
2426 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory: fb offset 0x%x\n", DeviceExtension->ulFrameBufferOffset));
2427
2428 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
2429
2430 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
2431#ifndef VBOX_WITH_HGSMI
2432 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize
2433 + DeviceExtension->pPrimary->u.primary.ulDisplayInformationSize;
2434#else
2435 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
2436#endif /* VBOX_WITH_HGSMI */
2437
2438 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
2439 &MapInformation->VideoRamLength, &inIoSpace,
2440 &MapInformation->VideoRamBase);
2441
2442 if (Status == NO_ERROR)
2443 {
2444 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
2445 MapInformation->FrameBufferLength =
2446 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
2447 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
2448 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
2449
2450 /* Save the new framebuffer size */
2451 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
2452#ifdef VBOX_WITH_HGSMI
2453 HGSMIAreaInitialize (&DeviceExtension->areaDisplay,
2454 MapInformation->FrameBufferBase,
2455 MapInformation->FrameBufferLength,
2456 DeviceExtension->ulFrameBufferOffset);
2457#endif /* VBOX_WITH_HGSMI */
2458 return TRUE;
2459 }
2460
2461 return FALSE;
2462}
2463
2464/**
2465 * VBoxVideoUnmapVideoMemory
2466 *
2467 * Releases a mapping between the virtual address space and the adapter's
2468 * frame buffer and video RAM.
2469 */
2470BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2471 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
2472{
2473 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
2474#ifdef VBOX_WITH_HGSMI
2475 HGSMIAreaClear (&DeviceExtension->areaDisplay);
2476#endif /* VBOX_WITH_HGSMI */
2477 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
2478 return TRUE;
2479}
2480
2481/**
2482 * VBoxVideoQueryNumAvailModes
2483 *
2484 * Returns the number of video modes supported by the adapter and the size
2485 * in bytes of the video mode information, which can be used to allocate a
2486 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
2487 */
2488BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
2489 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
2490{
2491 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
2492 /* calculate the video modes table */
2493 VBoxBuildModesTable(DeviceExtension);
2494 Modes->NumModes = gNumVideoModes;
2495 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
2496 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
2497 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
2498 return TRUE;
2499}
2500
2501/**
2502 * VBoxVideoQueryAvailModes
2503 *
2504 * Returns information about each video mode supported by the adapter.
2505 */
2506BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
2507 PVIDEO_MODE_INFORMATION ReturnedModes,
2508 PSTATUS_BLOCK StatusBlock)
2509{
2510 ULONG Size;
2511
2512 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
2513
2514 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
2515 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
2516 StatusBlock->Information = Size;
2517
2518 return TRUE;
2519}
2520
2521/**
2522 * VBoxVideoQueryCurrentMode
2523 *
2524 * Returns information about current video mode.
2525 */
2526BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2527 PVIDEO_MODE_INFORMATION VideoModeInfo,
2528 PSTATUS_BLOCK StatusBlock)
2529{
2530 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
2531
2532 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
2533 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
2534
2535 return TRUE;
2536}
2537#endif /* ifndef VBOXWDDM */
2538/*
2539 * VBoxVideoSetColorRegisters
2540 *
2541 * Sets the adapter's color registers to the specified RGB values. There
2542 * are code paths in this function, one generic and one for VGA compatible
2543 * controllers. The latter is needed for Bochs, where the generic one isn't
2544 * yet implemented.
2545 */
2546
2547BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
2548 PDEVICE_EXTENSION DeviceExtension,
2549 PVIDEO_CLUT ColorLookUpTable,
2550 PSTATUS_BLOCK StatusBlock)
2551{
2552 LONG Entry;
2553
2554 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
2555
2556 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
2557 return FALSE;
2558
2559 for (Entry = ColorLookUpTable->FirstEntry;
2560 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
2561 Entry++)
2562 {
2563 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c8, (UCHAR)Entry);
2564 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
2565 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
2566 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
2567 }
2568
2569 return TRUE;
2570}
2571
2572VP_STATUS VBoxVideoGetChildDescriptor(
2573 PVOID HwDeviceExtension,
2574 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
2575 PVIDEO_CHILD_TYPE VideoChildType,
2576 PUCHAR pChildDescriptor,
2577 PULONG pUId,
2578 PULONG pUnused)
2579{
2580 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
2581 HwDeviceExtension, ChildEnumInfo));
2582
2583 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
2584
2585 if (ChildEnumInfo->ChildIndex > 0)
2586 {
2587 if ((int)ChildEnumInfo->ChildIndex <= pDevExt->pPrimary->u.primary.cDisplays)
2588 {
2589 *VideoChildType = Monitor;
2590 *pUId = ChildEnumInfo->ChildIndex;
2591
2592 return VIDEO_ENUM_MORE_DEVICES;
2593 }
2594 }
2595
2596 return ERROR_NO_MORE_DEVICES;
2597}
2598
2599
2600static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
2601{
2602 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
2603 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
2604
2605 if (pPrimaryDevExt)
2606 {
2607 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
2608
2609 if (req)
2610 {
2611 int rc = VbglGRPerform (&req->header);
2612
2613 if (RT_FAILURE(rc) || RT_FAILURE(req->header.rc))
2614 {
2615 dprintf(("VBoxVideo::vbvaFlush: rc = %Rrc, VMMDev rc = %Rrc!!!\n", rc, req->header.rc));
2616 }
2617 }
2618 }
2619
2620 return;
2621}
2622
2623int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
2624{
2625 int rc = VINF_SUCCESS;
2626
2627 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
2628
2629 /*
2630 * Query the VMMDev memory pointer. There we need VBVAMemory.
2631 */
2632 VMMDevMemory *pVMMDevMemory = NULL;
2633
2634 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
2635
2636 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
2637
2638 if (pDevExt->iDevice > 0)
2639 {
2640 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
2641
2642 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
2643 pDevExt->iDevice));
2644
2645 if ( ulEnable
2646 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
2647 {
2648 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2649 pVbvaResult->pfnFlush = vboxVbvaFlush;
2650 pVbvaResult->pvFlush = pDevExt;
2651 }
2652 else
2653 {
2654 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
2655 }
2656
2657 return rc;
2658 }
2659
2660 if (RT_SUCCESS(rc))
2661 {
2662 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
2663 if (pDevExt->u.primary.pvReqFlush == NULL)
2664 {
2665 VMMDevVideoAccelFlush *req = NULL;
2666
2667 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2668 sizeof (VMMDevVideoAccelFlush),
2669 VMMDevReq_VideoAccelFlush);
2670
2671 if (RT_SUCCESS (rc))
2672 {
2673 pDevExt->u.primary.pvReqFlush = req;
2674 }
2675 else
2676 {
2677 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Rrc!!!\n", rc));
2678 }
2679 }
2680 }
2681 else
2682 {
2683 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Rrc!!!\n", rc));
2684 }
2685
2686 if (RT_SUCCESS(rc))
2687 {
2688 ULONG ulEnabled = 0;
2689
2690 /*
2691 * Tell host that VBVA status is changed.
2692 */
2693 VMMDevVideoAccelEnable *req = NULL;
2694
2695 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2696 sizeof (VMMDevVideoAccelEnable),
2697 VMMDevReq_VideoAccelEnable);
2698
2699 if (RT_SUCCESS(rc))
2700 {
2701 req->u32Enable = ulEnable;
2702 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2703 req->fu32Status = 0;
2704
2705 rc = VbglGRPerform (&req->header);
2706
2707 if (RT_SUCCESS(rc) && RT_SUCCESS(req->header.rc))
2708 {
2709 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
2710 {
2711 /*
2712 * Initialize the result information and VBVA memory.
2713 */
2714 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
2715 {
2716 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2717 pVbvaResult->pfnFlush = vboxVbvaFlush;
2718 pVbvaResult->pvFlush = pDevExt;
2719 ulEnabled = 1;
2720 }
2721 else
2722 {
2723 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
2724 }
2725
2726 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
2727 }
2728 else
2729 {
2730 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
2731
2732 /* Disable VBVA for old hosts. */
2733 req->u32Enable = 0;
2734 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2735 req->fu32Status = 0;
2736
2737 VbglGRPerform (&req->header);
2738
2739 rc = VERR_NOT_SUPPORTED;
2740 }
2741 }
2742 else
2743 {
2744 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Rrc, VMMDev rc = %Rrc!!!\n", rc, req->header.rc));
2745
2746 if (RT_SUCCESS(rc))
2747 {
2748 rc = req->header.rc;
2749 }
2750 }
2751
2752 VbglGRFree (&req->header);
2753 }
2754 else
2755 {
2756 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Rrc!!!\n", rc));
2757 }
2758
2759 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
2760 }
2761
2762 return rc;
2763}
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