VirtualBox

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

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

video hw accel: guest driver -> host framebuffer commands processing impl

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