VirtualBox

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

Last change on this file since 17704 was 17704, checked in by vboxsync, 16 years ago

HGSMI: the windows guest display drivers.

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

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