VirtualBox

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

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

HGSMI: windows guest video driver.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 93.1 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 ULONG ulAvailable = PrimaryExtension->u.primary.cbVRAM
735 - PrimaryExtension->u.primary.cbMiniportHeap
736 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
737
738 /* Size of a framebuffer. */
739
740 ULONG ulSize = ulAvailable / PrimaryExtension->u.primary.cDisplays;
741
742 /* Align down to 4096 bytes. */
743 ulSize &= ~0xFFF;
744
745 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X\n",
746 PrimaryExtension->u.primary.cbVRAM, PrimaryExtension->u.primary.cDisplays,
747 ulSize, ulSize * PrimaryExtension->u.primary.cDisplays,
748 ulAvailable - ulSize * PrimaryExtension->u.primary.cDisplays));
749
750 if (ulSize > VBOX_VIDEO_DISPLAY_INFORMATION_SIZE)
751 {
752 /* Compute the size of the framebuffer. */
753 ulSize -= VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
754 }
755 else
756 {
757 /* Should not really get here. But still do it safely. */
758 ulSize = 0;
759 }
760
761 /* Update the primary info. */
762 PrimaryExtension->u.primary.ulMaxFrameBufferSize = ulSize;
763 PrimaryExtension->u.primary.ulDisplayInformationSize = VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
764
765 /* Update the per extension info. */
766 PDEVICE_EXTENSION Extension = PrimaryExtension;
767 ULONG ulFrameBufferOffset = 0;
768 while (Extension)
769 {
770 Extension->ulFrameBufferOffset = ulFrameBufferOffset;
771 /* That is assigned when a video mode is set. */
772 Extension->ulFrameBufferSize = 0;
773
774 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: [%d] ulFrameBufferOffset 0x%08X\n",
775 Extension->iDevice, ulFrameBufferOffset));
776
777 ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize
778 + PrimaryExtension->u.primary.ulDisplayInformationSize;
779
780 Extension = Extension->pNext;
781 }
782}
783
784int VBoxMapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv, ULONG ulOffset, ULONG ulSize)
785{
786 dprintf(("VBoxVideo::VBoxMapAdapterMemory 0x%08X[0x%X]\n", ulOffset, ulSize));
787
788 if (!ulSize)
789 {
790 dprintf(("Illegal length 0!\n"));
791 return ERROR_INVALID_PARAMETER;
792 }
793
794 PHYSICAL_ADDRESS FrameBuffer;
795 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + ulOffset;
796
797 PVOID VideoRamBase = NULL;
798 ULONG inIoSpace = 0;
799 ULONG VideoRamLength = ulSize;
800
801 VP_STATUS Status = VideoPortMapMemory (PrimaryExtension, FrameBuffer,
802 &VideoRamLength, &inIoSpace,
803 &VideoRamBase);
804
805 if (Status == NO_ERROR)
806 {
807 *ppv = VideoRamBase;
808 }
809
810 dprintf(("VBoxVideo::VBoxMapAdapterMemory rc = %d\n", Status));
811
812 return Status;
813}
814
815void VBoxUnmapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv)
816{
817 dprintf(("VBoxVideo::VBoxMapAdapterMemory\n"));
818
819 if (*ppv)
820 {
821 VideoPortUnmapMemory(PrimaryExtension, *ppv, NULL);
822 }
823
824 *ppv = NULL;
825}
826
827static void vboxQueryConf (PDEVICE_EXTENSION PrimaryExtension, uint32_t u32Index, ULONG *pulValue)
828{
829 dprintf(("VBoxVideo::vboxQueryConf: u32Index = %d\n", u32Index));
830
831 typedef struct _VBOXVIDEOQCONF32
832 {
833 VBOXVIDEOINFOHDR hdrQuery;
834 VBOXVIDEOINFOQUERYCONF32 query;
835 VBOXVIDEOINFOHDR hdrEnd;
836 } VBOXVIDEOQCONF32;
837
838 VBOXVIDEOQCONF32 *p = (VBOXVIDEOQCONF32 *)PrimaryExtension->u.primary.pvAdapterInformation;
839
840 p->hdrQuery.u8Type = VBOX_VIDEO_INFO_TYPE_QUERY_CONF32;
841 p->hdrQuery.u8Reserved = 0;
842 p->hdrQuery.u16Length = sizeof (VBOXVIDEOINFOQUERYCONF32);
843
844 p->query.u32Index = u32Index;
845 p->query.u32Value = 0;
846
847 p->hdrEnd.u8Type = VBOX_VIDEO_INFO_TYPE_END;
848 p->hdrEnd.u8Reserved = 0;
849 p->hdrEnd.u16Length = 0;
850
851 /* Let the host to process the commands. */
852 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
853 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY);
854
855 *pulValue = (ULONG)p->query.u32Value;
856
857 dprintf(("VBoxVideo::vboxQueryConf: u32Value = %d\n", p->query.u32Value));
858}
859
860static void vboxSetupAdapterInfo (PDEVICE_EXTENSION PrimaryExtension)
861{
862 dprintf(("VBoxVideo::vboxSetupAdapterInfo\n"));
863
864 VBOXVIDEOINFOHDR *pHdr;
865
866 uint8_t *pu8 = (uint8_t *)PrimaryExtension->u.primary.pvAdapterInformation;
867
868 PDEVICE_EXTENSION Extension = PrimaryExtension;
869 while (Extension)
870 {
871 pHdr = (VBOXVIDEOINFOHDR *)pu8;
872 pu8 += sizeof (VBOXVIDEOINFOHDR);
873
874 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_DISPLAY;
875 pHdr->u8Reserved = 0;
876 pHdr->u16Length = sizeof (VBOXVIDEOINFODISPLAY);
877
878 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8;
879 pu8 += sizeof (VBOXVIDEOINFODISPLAY);
880
881 pDisplay->u32Index = Extension->iDevice;
882 pDisplay->u32Offset = Extension->ulFrameBufferOffset;
883 pDisplay->u32FramebufferSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
884 pDisplay->u32InformationSize = PrimaryExtension->u.primary.ulDisplayInformationSize;
885
886 Extension = Extension->pNext;
887 }
888
889
890 /* The heap description. */
891 pHdr = (VBOXVIDEOINFOHDR *)pu8;
892 pu8 += sizeof (VBOXVIDEOINFOHDR);
893
894 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_NV_HEAP;
895 pHdr->u8Reserved = 0;
896 pHdr->u16Length = sizeof (VBOXVIDEOINFONVHEAP);
897
898 VBOXVIDEOINFONVHEAP *pHeap = (VBOXVIDEOINFONVHEAP *)pu8;
899 pu8 += sizeof (VBOXVIDEOINFONVHEAP);
900
901 pHeap->u32HeapOffset = PrimaryExtension->u.primary.cbVRAM
902 - PrimaryExtension->u.primary.cbMiniportHeap
903 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
904 pHeap->u32HeapSize = PrimaryExtension->u.primary.cbMiniportHeap;
905
906
907 /* The END marker. */
908 pHdr = (VBOXVIDEOINFOHDR *)pu8;
909 pu8 += sizeof (VBOXVIDEOINFOHDR);
910
911 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_END;
912 pHdr->u8Reserved = 0;
913 pHdr->u16Length = 0;
914
915 /* Inform the host about the display configuration. */
916 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
917 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY);
918
919 dprintf(("VBoxVideo::vboxSetupAdapterInfo finished\n"));
920}
921
922/**
923 * Helper function to register secondary displays (DualView). Note that this will not
924 * be available on pre-XP versions, and some editions on XP will fail because they are
925 * intentionally crippled.
926 */
927VOID VBoxSetupDisplays(PDEVICE_EXTENSION PrimaryExtension, PVIDEO_PORT_CONFIG_INFO pConfigInfo, ULONG AdapterMemorySize)
928{
929 VP_STATUS rc = NO_ERROR;
930
931 dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
932 PrimaryExtension));
933
934 /* Preinitialize the primary extension. */
935 PrimaryExtension->pNext = NULL;
936 PrimaryExtension->pPrimary = PrimaryExtension;
937 PrimaryExtension->iDevice = 0;
938 PrimaryExtension->ulFrameBufferOffset = 0;
939 PrimaryExtension->ulFrameBufferSize = 0;
940 PrimaryExtension->u.primary.ulVbvaEnabled = 0;
941 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
942 PrimaryExtension->u.primary.cDisplays = 1;
943 PrimaryExtension->u.primary.cbVRAM = AdapterMemorySize;
944 PrimaryExtension->u.primary.cbMiniportHeap = 0;
945 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
946 PrimaryExtension->u.primary.pvAdapterInformation = NULL;
947 PrimaryExtension->u.primary.ulMaxFrameBufferSize = 0;
948 PrimaryExtension->u.primary.ulDisplayInformationSize = 0;
949
950 /* Verify whether the HW supports VirtualBox extensions. */
951 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
952 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_VBOX_VIDEO);
953
954 if (VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA) == VBE_DISPI_ID_VBOX_VIDEO)
955 {
956 PrimaryExtension->u.primary.bVBoxVideoSupported = TRUE;
957 }
958
959 dprintf(("VBoxVideo::VBoxSetupDisplays: bVBoxVideoSupported = %d\n",
960 PrimaryExtension->u.primary.bVBoxVideoSupported));
961
962 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
963 {
964 /* Map the adapter information. It will be needed to query some configuration values. */
965 rc = VBoxMapAdapterMemory (PrimaryExtension,
966 &PrimaryExtension->u.primary.pvAdapterInformation,
967 PrimaryExtension->u.primary.cbVRAM - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE,
968 VBOX_VIDEO_ADAPTER_INFORMATION_SIZE
969 );
970 if (rc != NO_ERROR)
971 {
972 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
973 rc));
974
975 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
976 }
977 }
978
979 /* Setup the non-volatile heap and the adapter memory. */
980 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
981 {
982 /* Query the size of the non-volatile heap. */
983 ULONG cbMiniportHeap = 0;
984 vboxQueryConf (PrimaryExtension, VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE, &cbMiniportHeap);
985
986 /* Do not allow too big heap. 50% of VRAM should be enough. */
987 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 2 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
988
989 if (cbMiniportHeap > cbMiniportHeapMaxSize)
990 {
991 cbMiniportHeap = cbMiniportHeapMaxSize;
992 }
993
994 /* Round up to 4096. */
995 PrimaryExtension->u.primary.cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
996
997 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
998 cbMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap, cbMiniportHeapMaxSize));
999
1000 /* Map the heap region and the adapter information area.
1001 *
1002 * Note: the heap will be used by display drivers, possibly by a few instances
1003 * in multimonitor configuration, but the memory is mapped here ones.
1004 * It is assumed that all display drivers and the miniport has the SAME
1005 * virtual address space.
1006 *
1007 */
1008 rc = VBoxMapAdapterMemory (PrimaryExtension,
1009 &PrimaryExtension->u.primary.pvMiniportHeap,
1010 PrimaryExtension->u.primary.cbVRAM
1011 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE
1012 - PrimaryExtension->u.primary.cbMiniportHeap,
1013 PrimaryExtension->u.primary.cbMiniportHeap
1014 );
1015
1016 if (rc != NO_ERROR)
1017 {
1018 PrimaryExtension->u.primary.cbMiniportHeap = 0;
1019 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1020 }
1021 }
1022
1023 /* Check whether the guest supports multimonitors. */
1024 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1025 {
1026 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
1027 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
1028
1029 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
1030 if (vboxQueryWinVersion() > WINNT4)
1031 {
1032 /* This bluescreens on NT4, hence the above version check */
1033 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
1034 (PrimaryExtension,
1035 (PUCHAR)"VideoPortCreateSecondaryDisplay");
1036 }
1037
1038 if (pfnCreateSecondaryDisplay != NULL)
1039 {
1040 /* Query the configured number of displays. */
1041 ULONG cDisplays = 0;
1042 vboxQueryConf (PrimaryExtension, VBOX_VIDEO_QCI32_MONITOR_COUNT, &cDisplays);
1043
1044 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
1045 cDisplays));
1046
1047 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
1048 {
1049 /* Host reported some bad value. Continue in the 1 screen mode. */
1050 cDisplays = 1;
1051 }
1052
1053 PDEVICE_EXTENSION pPrev = PrimaryExtension;
1054
1055 ULONG iDisplay;
1056 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
1057 {
1058 PDEVICE_EXTENSION SecondaryExtension = NULL;
1059 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
1060
1061 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
1062 rc, SecondaryExtension));
1063
1064 if (rc != NO_ERROR)
1065 {
1066 break;
1067 }
1068
1069 SecondaryExtension->pNext = NULL;
1070 SecondaryExtension->pPrimary = PrimaryExtension;
1071 SecondaryExtension->iDevice = iDisplay;
1072 SecondaryExtension->ulFrameBufferOffset = 0;
1073 SecondaryExtension->ulFrameBufferSize = 0;
1074 SecondaryExtension->u.secondary.bEnabled = FALSE;
1075
1076 /* Update the list pointers. */
1077 pPrev->pNext = SecondaryExtension;
1078 pPrev = SecondaryExtension;
1079
1080 /* Take the successfully created display into account. */
1081 PrimaryExtension->u.primary.cDisplays++;
1082 }
1083
1084 /* Failure to create secondary displays is not fatal */
1085 rc = NO_ERROR;
1086 }
1087 }
1088
1089 /* Now when the number of monitors is known and extensions are created,
1090 * calculate the layout of framebuffers.
1091 */
1092 VBoxComputeFrameBufferSizes (PrimaryExtension);
1093
1094 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1095 {
1096 /* Setup the information for the host. */
1097 vboxSetupAdapterInfo (PrimaryExtension);
1098 }
1099 else
1100 {
1101 /* Unmap the memory if VBoxVideo is not supported. */
1102 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvMiniportHeap);
1103 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvAdapterInformation);
1104 }
1105
1106 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
1107}
1108
1109VP_STATUS VBoxVideoFindAdapter(IN PVOID HwDeviceExtension,
1110 IN PVOID HwContext, IN PWSTR ArgumentString,
1111 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
1112 OUT PUCHAR Again)
1113{
1114 VP_STATUS rc;
1115 USHORT DispiId;
1116 ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
1117 VIDEO_ACCESS_RANGE AccessRanges[] =
1118 {
1119 {
1120 {0, VBE_DISPI_LFB_PHYSICAL_ADDRESS},
1121 VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES,
1122 0,
1123 FALSE,
1124 FALSE,
1125 0
1126 }
1127 };
1128
1129 dprintf(("VBoxVideo::VBoxVideoFindAdapter\n"));
1130
1131 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1132 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
1133 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
1134 if (DispiId == VBE_DISPI_ID2)
1135 {
1136 dprintf(("VBoxVideo::VBoxVideoFoundAdapter: found the VBE card\n"));
1137 /*
1138 * Write some hardware information to registry, so that
1139 * it's visible in Windows property dialog.
1140 */
1141
1142 rc = VideoPortSetRegistryParameters(
1143 HwDeviceExtension,
1144 L"HardwareInformation.ChipType",
1145 VBoxChipType,
1146 sizeof(VBoxChipType));
1147
1148 rc = VideoPortSetRegistryParameters(
1149 HwDeviceExtension,
1150 L"HardwareInformation.DacType",
1151 VBoxDACType,
1152 sizeof(VBoxDACType));
1153
1154 /*
1155 * Query the adapter's memory size. It's a bit of a hack, we just read
1156 * an ULONG from the data port without setting an index before.
1157 */
1158 AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
1159 rc = VideoPortSetRegistryParameters(
1160 HwDeviceExtension,
1161 L"HardwareInformation.MemorySize",
1162 &AdapterMemorySize,
1163 sizeof(ULONG));
1164
1165 rc = VideoPortSetRegistryParameters(
1166 HwDeviceExtension,
1167 L"HardwareInformation.AdapterString",
1168 VBoxAdapterString,
1169 sizeof(VBoxAdapterString));
1170
1171 rc = VideoPortSetRegistryParameters(
1172 HwDeviceExtension,
1173 L"HardwareInformation.BiosString",
1174 VBoxBiosString,
1175 sizeof(VBoxBiosString));
1176
1177 rc = VideoPortVerifyAccessRanges(HwDeviceExtension, 1, AccessRanges);
1178 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortVerifyAccessRanges returned 0x%x\n", rc));
1179 // @todo for some reason, I get an ERROR_INVALID_PARAMETER from NT4 SP0
1180 // It does not seem to like getting me these port addresses. So I just
1181 // pretend success to make the driver work.
1182 rc = NO_ERROR;
1183
1184#ifndef VBOX_WITH_HGSMI
1185 /* Initialize VBoxGuest library */
1186 rc = VbglInit ();
1187
1188 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
1189
1190 /* Setup the Device Extension and if possible secondary displays. */
1191 VBoxSetupDisplays((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
1192#else
1193 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
1194 * code will be ifdef'ed and later removed.
1195 * The host will however support both old and new interface to keep compatibility
1196 * with old guest additions.
1197 */
1198 if (VBoxHGSMIIsSupported ())
1199 {
1200 LogRel(("VBoxVideo: using HGSMI\n"));
1201
1202 VBoxSetupDisplaysHGSMI((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
1203 }
1204#endif /* VBOX_WITH_HGSMI */
1205
1206 // pretend success to make the driver work.
1207 rc = NO_ERROR;
1208 } else
1209 {
1210 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
1211 rc = ERROR_DEV_NOT_EXIST;
1212 }
1213 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
1214 return rc;
1215}
1216
1217/**
1218 * VBoxVideoInitialize
1219 *
1220 * Performs the first initialization of the adapter, after the HAL has given
1221 * up control of the video hardware to the video port driver.
1222 */
1223BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
1224{
1225 VP_STATUS status;
1226
1227 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
1228
1229 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1230
1231 /* Initialize the request pointer. */
1232 pDevExt->u.primary.pvReqFlush = NULL;
1233
1234 /*
1235 * Get the last custom resolution
1236 */
1237 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1238 L"CustomXRes",
1239 FALSE,
1240 VBoxRegistryCallback,
1241 &gCustomXRes);
1242 if (status != NO_ERROR)
1243 gCustomXRes = 0;
1244 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1245 L"CustomYRes",
1246 FALSE,
1247 VBoxRegistryCallback,
1248 &gCustomYRes);
1249 if (status != NO_ERROR)
1250 gCustomYRes = 0;
1251 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1252 L"CustomBPP",
1253 FALSE,
1254 VBoxRegistryCallback,
1255 &gCustomBPP);
1256 if (status != NO_ERROR)
1257 gCustomBPP = 0;
1258
1259 dprintf(("VBoxVideo: got stored custom resolution %dx%dx%d\n", gCustomXRes, gCustomYRes, gCustomBPP));
1260
1261 return TRUE;
1262}
1263
1264/**
1265 * VBoxVideoStartIO
1266 *
1267 * Processes the specified Video Request Packet.
1268 */
1269BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
1270 PVIDEO_REQUEST_PACKET RequestPacket)
1271{
1272 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1273
1274 BOOLEAN Result;
1275
1276// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
1277
1278 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1279
1280 switch (RequestPacket->IoControlCode)
1281 {
1282 case IOCTL_VIDEO_SET_CURRENT_MODE:
1283 {
1284 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
1285 {
1286 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1287 return TRUE;
1288 }
1289 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1290 (PVIDEO_MODE)RequestPacket->InputBuffer,
1291 RequestPacket->StatusBlock);
1292 break;
1293 }
1294
1295 case IOCTL_VIDEO_RESET_DEVICE:
1296 {
1297 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
1298 RequestPacket->StatusBlock);
1299 break;
1300 }
1301
1302 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
1303 {
1304 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
1305 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1306 {
1307 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1308 return TRUE;
1309 }
1310 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1311 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1312 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
1313 RequestPacket->StatusBlock);
1314 break;
1315 }
1316
1317 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
1318 {
1319 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1320 {
1321 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1322 return TRUE;
1323 }
1324 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1325 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1326 RequestPacket->StatusBlock);
1327 break;
1328 }
1329
1330 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
1331 {
1332 PVIDEO_SHARE_MEMORY pShareMemory;
1333 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
1334 PHYSICAL_ADDRESS shareAddress;
1335 PVOID virtualAddress = NULL;
1336 ULONG sharedViewSize;
1337 ULONG inIoSpace = 0;
1338 VP_STATUS status;
1339
1340 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
1341
1342 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
1343 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
1344
1345 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1346 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1347 Result = FALSE;
1348 break;
1349 }
1350
1351 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1352
1353 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
1354 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
1355
1356 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));
1357 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
1358 Result = FALSE;
1359 break;
1360 }
1361
1362 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
1363
1364 virtualAddress = pShareMemory->ProcessHandle;
1365 sharedViewSize = pShareMemory->ViewSize;
1366
1367 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
1368
1369 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
1370 if (status != NO_ERROR)
1371 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
1372 Result = (status == NO_ERROR);
1373
1374 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
1375 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
1376 pShareMemoryInformation->VirtualAddress = virtualAddress;
1377 pShareMemoryInformation->SharedViewSize = sharedViewSize;
1378 break;
1379 }
1380
1381 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
1382 {
1383 PVIDEO_SHARE_MEMORY pShareMemory;
1384 VP_STATUS status;
1385
1386 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
1387
1388 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
1389 {
1390 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1391 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1392 Result = FALSE;
1393 break;
1394 }
1395
1396 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1397
1398 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
1399 if (status != NO_ERROR)
1400 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
1401 Result = (status == NO_ERROR);
1402 break;
1403 }
1404
1405 /*
1406 * The display driver asks us how many video modes we support
1407 * so that it can supply an appropriate buffer for the next call.
1408 */
1409 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
1410 {
1411 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
1412 {
1413 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1414 return TRUE;
1415 }
1416 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1417 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
1418 RequestPacket->StatusBlock);
1419 break;
1420 }
1421
1422 /*
1423 * The display driver asks us to provide a list of supported video modes
1424 * into a buffer it has allocated.
1425 */
1426 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
1427 {
1428 if (RequestPacket->OutputBufferLength <
1429 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
1430 {
1431 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1432 return TRUE;
1433 }
1434 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1435 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1436 RequestPacket->StatusBlock);
1437 break;
1438 }
1439
1440 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
1441 {
1442 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
1443 RequestPacket->InputBufferLength <
1444 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
1445 sizeof(VIDEO_CLUT))
1446 {
1447 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1448 return TRUE;
1449 }
1450 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
1451 (PVIDEO_CLUT)RequestPacket->InputBuffer,
1452 RequestPacket->StatusBlock);
1453 break;
1454 }
1455
1456 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
1457 {
1458 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
1459 {
1460 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1461 return TRUE;
1462 }
1463 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1464 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1465 RequestPacket->StatusBlock);
1466 break;
1467 }
1468
1469 // show the pointer
1470 case IOCTL_VIDEO_ENABLE_POINTER:
1471 {
1472 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
1473 // find out whether the host wants absolute positioning
1474 if (vboxQueryHostWantsAbsolute())
1475 {
1476 // tell the host to use the guest's pointer
1477 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1478
1479 /* Visible and No Shape means Show the pointer.
1480 * It is enough to init only this field.
1481 */
1482 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
1483
1484 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
1485
1486 if (!Result)
1487 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
1488 } else
1489 {
1490 // fallback to software pointer
1491 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1492 Result = FALSE;
1493 }
1494 break;
1495 }
1496
1497 // hide the pointer
1498 case IOCTL_VIDEO_DISABLE_POINTER:
1499 {
1500 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
1501 // find out whether the host wants absolute positioning
1502 if (vboxQueryHostWantsAbsolute())
1503 {
1504 // tell the host to hide pointer
1505 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1506
1507 /* Enable == 0 means no shape, not visible.
1508 * It is enough to init only this field.
1509 */
1510 PointerAttributes.Enable = 0;
1511
1512 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
1513
1514 if (!Result)
1515 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
1516 } else
1517 {
1518 // fallback to software pointer
1519 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1520 Result = FALSE;
1521 }
1522 break;
1523 }
1524
1525 /*
1526 * Change the pointer shape
1527 */
1528 case IOCTL_VIDEO_SET_POINTER_ATTR:
1529 {
1530 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
1531 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
1532 {
1533 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
1534 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1535 return TRUE;
1536 }
1537 // find out whether the host wants absolute positioning
1538 if (vboxQueryHostWantsAbsolute())
1539 {
1540 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
1541#if 0
1542 dprintf(("Pointer shape information:\n"
1543 "\tFlags: %d\n"
1544 "\tWidth: %d\n"
1545 "\tHeight: %d\n"
1546 "\tWidthInBytes: %d\n"
1547 "\tEnable: %d\n"
1548 "\tColumn: %d\n"
1549 "\tRow: %d\n",
1550 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
1551 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
1552 pPointerAttributes->Row));
1553 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
1554#endif
1555 Result = vboxUpdatePointerShape(pPointerAttributes, RequestPacket->InputBufferLength);
1556 if (!Result)
1557 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
1558 } else
1559 {
1560 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
1561 // fallback to software pointer
1562 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1563 Result = FALSE;
1564 }
1565 break;
1566 }
1567
1568 // query pointer information
1569 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
1570 {
1571 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
1572 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1573 Result = FALSE;
1574 break;
1575 }
1576
1577 // set the pointer position
1578 case IOCTL_VIDEO_SET_POINTER_POSITION:
1579 {
1580 /// @todo There is an issue when we disable pointer integration.
1581 // The guest pointer will be invisible. We have to somehow cause
1582 // the pointer attributes to be set again. But how? The same holds
1583 // true for the opposite case where we get two pointers.
1584
1585 //dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_POSITION\n"));
1586 // find out whether the host wants absolute positioning
1587 if (vboxQueryHostWantsAbsolute())
1588 {
1589 // @todo we are supposed to show currently invisible pointer?
1590 Result = TRUE;
1591 } else
1592 {
1593 // fallback to software pointer
1594 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1595 Result = FALSE;
1596 }
1597 break;
1598 }
1599
1600 // query the pointer position
1601 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
1602 {
1603 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
1604 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
1605 {
1606 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
1607 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1608 return TRUE;
1609 }
1610 Result = FALSE;
1611 uint16_t mousePosX;
1612 uint16_t mousePosY;
1613 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
1614 {
1615 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
1616 PVIDEO_MODE_INFORMATION ModeInfo;
1617 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
1618 // map from 0xFFFF to the current resolution
1619 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
1620 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
1621 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
1622 Result = TRUE;
1623 }
1624 if (!Result)
1625 {
1626 // fallback to software pointer
1627 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1628 }
1629 break;
1630 }
1631
1632 // Determine hardware cursor capabilities. We will always report that we are
1633 // very capable even though the host might not want to do pointer integration.
1634 // This is done because we can still return errors on the actual calls later to
1635 // make the display driver go to the fallback routines.
1636 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
1637 {
1638 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
1639 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
1640 {
1641 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
1642 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1643 return TRUE;
1644 }
1645 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
1646 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
1647 VIDEO_MODE_COLOR_POINTER |
1648 VIDEO_MODE_MONO_POINTER;
1649 // for now we go with 64x64 cursors
1650 pCaps->MaxWidth = 64;
1651 pCaps->MaxHeight = 64;
1652 // that doesn't seem to be relevant, VBoxDisp doesn't use it
1653 pCaps->HWPtrBitmapStart = -1;
1654 pCaps->HWPtrBitmapEnd = -1;
1655 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
1656 Result = TRUE;
1657 break;
1658 }
1659
1660 /* Attach/detach DualView devices */
1661 case IOCTL_VIDEO_SWITCH_DUALVIEW:
1662 {
1663 ULONG ulAttach;
1664
1665 ulAttach = *((PULONG)RequestPacket->InputBuffer);
1666 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
1667
1668 if (pDevExt->iDevice > 0)
1669 {
1670 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
1671 }
1672 Result = TRUE;
1673 break;
1674 }
1675
1676 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
1677 {
1678 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
1679
1680 if (pDevExt->pPrimary->u.primary.bVBoxVideoSupported)
1681 {
1682 /* The display driver must have prepared the monitor information. */
1683 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1684 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE + pDevExt->iDevice);
1685 }
1686 else
1687 {
1688 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1689 }
1690 Result = pDevExt->pPrimary->u.primary.bVBoxVideoSupported;
1691 break;
1692 }
1693
1694 case IOCTL_VIDEO_QUERY_DISPLAY_INFO:
1695 {
1696 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_DISPLAY_INFO\n"));
1697
1698 if (RequestPacket->OutputBufferLength < sizeof(QUERYDISPLAYINFORESULT))
1699 {
1700 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
1701 RequestPacket->OutputBufferLength, sizeof(QUERYDISPLAYINFORESULT)));
1702 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1703 return FALSE;
1704 }
1705
1706 QUERYDISPLAYINFORESULT *pDispInfo = (QUERYDISPLAYINFORESULT *)RequestPacket->OutputBuffer;
1707
1708 pDispInfo->iDevice = pDevExt->iDevice;
1709 pDispInfo->u32DisplayInfoSize = pDevExt->pPrimary->u.primary.ulDisplayInformationSize;
1710
1711 RequestPacket->StatusBlock->Information = sizeof(QUERYDISPLAYINFORESULT);
1712 Result = TRUE;
1713
1714 break;
1715 }
1716
1717 case IOCTL_VIDEO_VBVA_ENABLE:
1718 {
1719 int rc;
1720 ULONG ulEnable;
1721
1722 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
1723
1724 if (RequestPacket->InputBufferLength < sizeof(ULONG))
1725 {
1726 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
1727 RequestPacket->InputBufferLength, sizeof(ULONG)));
1728 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1729 return FALSE;
1730 }
1731
1732 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
1733 {
1734 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
1735 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
1736 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1737 return FALSE;
1738 }
1739
1740 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
1741 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
1742
1743 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
1744 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Rrc\n", rc));
1745
1746 if (RT_FAILURE (rc))
1747 {
1748 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
1749 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1750 return FALSE;
1751 }
1752
1753 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
1754 Result = TRUE;
1755
1756 break;
1757 }
1758
1759 /* Private ioctls */
1760 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
1761 {
1762 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
1763 int rc;
1764
1765 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
1766 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
1767 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
1768 {
1769 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
1770 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
1771 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1772 return FALSE;
1773 }
1774 /*
1775 * Inform the host about the visible region
1776 */
1777 VMMDevVideoSetVisibleRegion *req = NULL;
1778
1779 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
1780 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
1781 VMMDevReq_VideoSetVisibleRegion);
1782
1783 if (RT_SUCCESS(rc))
1784 {
1785 req->cRect = cRect;
1786 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
1787
1788 rc = VbglGRPerform (&req->header);
1789
1790 if (RT_SUCCESS(rc) && RT_SUCCESS(req->header.rc))
1791 {
1792 Result = TRUE;
1793 break;
1794 }
1795 }
1796 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x (hdr.rc=%x)\n", rc, (req) ? req->header.rc : -1));
1797 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1798 return FALSE;
1799 }
1800
1801#ifdef VBOX_WITH_HGSMI
1802 case IOCTL_VIDEO_QUERY_HGSMI_INFO:
1803 {
1804 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_HGSMI_INFO\n"));
1805
1806 if (RequestPacket->OutputBufferLength < sizeof(QUERYHGSMIRESULT))
1807 {
1808 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
1809 RequestPacket->OutputBufferLength, sizeof(QUERYHGSMIRESULT)));
1810 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1811 return FALSE;
1812 }
1813
1814 if (!pDevExt->pPrimary->u.primary.bHGSMI)
1815 {
1816 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1817 return FALSE;
1818 }
1819
1820 QUERYHGSMIRESULT *pInfo = (QUERYHGSMIRESULT *)RequestPacket->OutputBuffer;
1821
1822 pInfo->iDevice = pDevExt->iDevice;
1823 pInfo->ulFlags = 0;
1824
1825 /* Describes VRAM chunk for this display device. */
1826 pInfo->areaDisplay = pDevExt->areaDisplay;
1827
1828 RequestPacket->StatusBlock->Information = sizeof(QUERYHGSMIRESULT);
1829 Result = TRUE;
1830
1831 break;
1832 }
1833#endif /* VBOX_WITH_HGSMI */
1834
1835 default:
1836 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
1837 RequestPacket->IoControlCode,
1838 (RequestPacket->IoControlCode >> 2) & 0xFFF,
1839 (RequestPacket->IoControlCode >> 2) & 0xFFF));
1840 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1841 return FALSE;
1842 }
1843
1844 if (Result)
1845 RequestPacket->StatusBlock->Status = NO_ERROR;
1846 else
1847 RequestPacket->StatusBlock->Information = 0;
1848
1849// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
1850
1851 return TRUE;
1852}
1853
1854/**
1855 * VBoxVideoReset HW
1856 *
1857 * Resets the video hardware.
1858 */
1859BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
1860{
1861 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
1862
1863 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1864
1865 if (pDevExt->iDevice > 0)
1866 {
1867 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
1868 pDevExt->iDevice));
1869 return TRUE;
1870 }
1871
1872 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1873 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
1874
1875 if (pDevExt->u.primary.pvReqFlush != NULL)
1876 {
1877 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
1878 pDevExt->u.primary.pvReqFlush = NULL;
1879 }
1880
1881 VbglTerminate ();
1882
1883 VBoxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvMiniportHeap);
1884 VBoxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvAdapterInformation);
1885
1886 return TRUE;
1887}
1888
1889/**
1890 * VBoxVideoGetPowerState
1891 *
1892 * Queries whether the device can support the requested power state.
1893 */
1894VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
1895 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
1896{
1897 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
1898 return NO_ERROR;
1899}
1900
1901/**
1902 * VBoxVideoSetPowerState
1903 *
1904 * Sets the power state of the specified device
1905 */
1906VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
1907 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
1908{
1909 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
1910 return NO_ERROR;
1911}
1912
1913/**
1914 * VBoxVideoSetGraphicsCap
1915 *
1916 * Tells the host whether or not we currently support graphics in the
1917 * additions
1918 */
1919BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
1920{
1921 VMMDevReqGuestCapabilities2 *req = NULL;
1922 int rc;
1923
1924 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
1925 sizeof (VMMDevReqGuestCapabilities2),
1926 VMMDevReq_SetGuestCapabilities);
1927
1928 if (!RT_SUCCESS(rc))
1929 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
1930 else
1931 {
1932 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
1933 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
1934
1935 rc = VbglGRPerform (&req->header);
1936 if (!RT_SUCCESS(rc) || !RT_SUCCESS(req->header.rc))
1937 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc, VMMDev rc = %Rrc\n", rc, req->header.rc));
1938 if (RT_SUCCESS(rc))
1939 rc = req->header.rc;
1940 }
1941 if (req != NULL)
1942 VbglGRFree (&req->header);
1943 return RT_SUCCESS(rc);
1944}
1945
1946/**
1947 * VBoxVideoSetCurrentMode
1948 *
1949 * Sets the adapter to the specified operating mode.
1950 */
1951BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
1952 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
1953{
1954 PVIDEO_MODE_INFORMATION ModeInfo;
1955
1956 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
1957
1958 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
1959 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
1960 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
1961 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
1962
1963 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
1964 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
1965 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
1966
1967 if (DeviceExtension->iDevice > 0)
1968 {
1969 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
1970 DeviceExtension->iDevice));
1971 return TRUE;
1972 }
1973
1974 /* set the mode characteristics */
1975 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
1976 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenWidth);
1977 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
1978 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenHeight);
1979 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
1980 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->BitsPerPlane);
1981 /* enable the mode */
1982 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1983 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
1984 /** @todo read from the port to see if the mode switch was successful */
1985
1986 /* Tell the host that we now support graphics in the additions.
1987 * @todo: Keep old behaviour, because VBoxVideoResetDevice is called on every graphics
1988 * mode switch and causes an OFF/ON sequence which is not handled by frontends
1989 * (for example Qt GUI debug build asserts when seamless is being enabled).
1990 */
1991 // VBoxVideoSetGraphicsCap(TRUE);
1992 return TRUE;
1993}
1994
1995/*
1996 * VBoxVideoResetDevice
1997 *
1998 * Resets the video hardware to the default mode, to which it was initialized
1999 * at system boot.
2000 */
2001
2002BOOLEAN FASTCALL VBoxVideoResetDevice(
2003 PDEVICE_EXTENSION DeviceExtension,
2004 PSTATUS_BLOCK StatusBlock)
2005{
2006 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
2007
2008 if (DeviceExtension->iDevice > 0)
2009 {
2010 /* If the device is the secondary display, however, it is recommended that no action be taken. */
2011 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
2012 DeviceExtension->iDevice));
2013 return TRUE;
2014 }
2015
2016#if 0
2017 /* Don't disable the extended video mode. This would only switch the video mode
2018 * to <current width> x <current height> x 0 bpp which is not what we want. And
2019 * even worse, it causes an disturbing additional mode switch */
2020 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2021 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2022#endif
2023
2024 /* Tell the host that we no longer support graphics in the additions
2025 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
2026 */
2027 // VBoxVideoSetGraphicsCap(FALSE);
2028 return TRUE;
2029}
2030
2031/**
2032 * VBoxVideoMapVideoMemory
2033 *
2034 * Maps the video hardware frame buffer and video RAM into the virtual address
2035 * space of the requestor.
2036 */
2037BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2038 PVIDEO_MEMORY RequestedAddress,
2039 PVIDEO_MEMORY_INFORMATION MapInformation,
2040 PSTATUS_BLOCK StatusBlock)
2041{
2042 PHYSICAL_ADDRESS FrameBuffer;
2043 ULONG inIoSpace = 0;
2044 VP_STATUS Status;
2045
2046 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory\n"));
2047
2048 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
2049
2050 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
2051 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize
2052 + DeviceExtension->pPrimary->u.primary.ulDisplayInformationSize;
2053
2054 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
2055 &MapInformation->VideoRamLength, &inIoSpace,
2056 &MapInformation->VideoRamBase);
2057
2058 if (Status == NO_ERROR)
2059 {
2060 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
2061 MapInformation->FrameBufferLength =
2062 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
2063 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
2064 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
2065
2066 /* Save the new framebuffer size */
2067 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
2068#ifdef VBOX_WITH_HGSMI
2069 HGSMIAreaInitialize (&DeviceExtension->areaDisplay,
2070 MapInformation->FrameBufferBase,
2071 MapInformation->FrameBufferLength,
2072 DeviceExtension->ulFrameBufferOffset);
2073#endif /* VBOX_WITH_HGSMI */
2074 return TRUE;
2075 }
2076
2077 return FALSE;
2078}
2079
2080/**
2081 * VBoxVideoUnmapVideoMemory
2082 *
2083 * Releases a mapping between the virtual address space and the adapter's
2084 * frame buffer and video RAM.
2085 */
2086BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2087 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
2088{
2089 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
2090#ifdef VBOX_WITH_HGSMI
2091 HGSMIAreaClear (&DeviceExtension->areaDisplay);
2092#endif /* VBOX_WITH_HGSMI */
2093 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
2094 return TRUE;
2095}
2096
2097/**
2098 * VBoxVideoQueryNumAvailModes
2099 *
2100 * Returns the number of video modes supported by the adapter and the size
2101 * in bytes of the video mode information, which can be used to allocate a
2102 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
2103 */
2104BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
2105 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
2106{
2107 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
2108 /* calculate the video modes table */
2109 VBoxBuildModesTable(DeviceExtension);
2110 Modes->NumModes = gNumVideoModes;
2111 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
2112 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
2113 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
2114 return TRUE;
2115}
2116
2117/**
2118 * VBoxVideoQueryAvailModes
2119 *
2120 * Returns information about each video mode supported by the adapter.
2121 */
2122BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
2123 PVIDEO_MODE_INFORMATION ReturnedModes,
2124 PSTATUS_BLOCK StatusBlock)
2125{
2126 ULONG Size;
2127
2128 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
2129
2130 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
2131 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
2132 StatusBlock->Information = Size;
2133
2134 return TRUE;
2135}
2136
2137/**
2138 * VBoxVideoQueryCurrentMode
2139 *
2140 * Returns information about current video mode.
2141 */
2142BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2143 PVIDEO_MODE_INFORMATION VideoModeInfo,
2144 PSTATUS_BLOCK StatusBlock)
2145{
2146 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
2147
2148 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
2149 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
2150
2151 return TRUE;
2152}
2153
2154/*
2155 * VBoxVideoSetColorRegisters
2156 *
2157 * Sets the adapter's color registers to the specified RGB values. There
2158 * are code paths in this function, one generic and one for VGA compatible
2159 * controllers. The latter is needed for Bochs, where the generic one isn't
2160 * yet implemented.
2161 */
2162
2163BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
2164 PDEVICE_EXTENSION DeviceExtension,
2165 PVIDEO_CLUT ColorLookUpTable,
2166 PSTATUS_BLOCK StatusBlock)
2167{
2168 LONG Entry;
2169
2170 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
2171
2172 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
2173 return FALSE;
2174
2175 for (Entry = ColorLookUpTable->FirstEntry;
2176 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
2177 Entry++)
2178 {
2179 VideoPortWritePortUchar((PUCHAR)0x03c8, (UCHAR)Entry);
2180 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
2181 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
2182 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
2183 }
2184
2185 return TRUE;
2186}
2187
2188VP_STATUS VBoxVideoGetChildDescriptor(
2189 PVOID HwDeviceExtension,
2190 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
2191 PVIDEO_CHILD_TYPE VideoChildType,
2192 PUCHAR pChildDescriptor,
2193 PULONG pUId,
2194 PULONG pUnused)
2195{
2196 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
2197 HwDeviceExtension, ChildEnumInfo));
2198
2199 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
2200
2201 if (ChildEnumInfo->ChildIndex > 0)
2202 {
2203 if ((int)ChildEnumInfo->ChildIndex <= pDevExt->pPrimary->u.primary.cDisplays)
2204 {
2205 *VideoChildType = Monitor;
2206 *pUId = ChildEnumInfo->ChildIndex;
2207
2208 return VIDEO_ENUM_MORE_DEVICES;
2209 }
2210 }
2211
2212 return ERROR_NO_MORE_DEVICES;
2213}
2214
2215
2216static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
2217{
2218 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
2219 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
2220
2221 if (pPrimaryDevExt)
2222 {
2223 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
2224
2225 if (req)
2226 {
2227 int rc = VbglGRPerform (&req->header);
2228
2229 if (RT_FAILURE(rc) || RT_FAILURE(req->header.rc))
2230 {
2231 dprintf(("VBoxVideo::vbvaFlush: rc = %Rrc, VMMDev rc = %Rrc!!!\n", rc, req->header.rc));
2232 }
2233 }
2234 }
2235
2236 return;
2237}
2238
2239int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
2240{
2241 int rc = VINF_SUCCESS;
2242
2243 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
2244
2245 /*
2246 * Query the VMMDev memory pointer. There we need VBVAMemory.
2247 */
2248 VMMDevMemory *pVMMDevMemory = NULL;
2249
2250 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
2251
2252 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
2253
2254 if (pDevExt->iDevice > 0)
2255 {
2256 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
2257
2258 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
2259 pDevExt->iDevice));
2260
2261 if ( ulEnable
2262 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
2263 {
2264 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2265 pVbvaResult->pfnFlush = vboxVbvaFlush;
2266 pVbvaResult->pvFlush = pDevExt;
2267 }
2268 else
2269 {
2270 VideoPortZeroMemory(&pVbvaResult, sizeof(VBVAENABLERESULT));
2271 }
2272
2273 return rc;
2274 }
2275
2276 if (RT_SUCCESS(rc))
2277 {
2278 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
2279 if (pDevExt->u.primary.pvReqFlush == NULL)
2280 {
2281 VMMDevVideoAccelFlush *req = NULL;
2282
2283 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2284 sizeof (VMMDevVideoAccelFlush),
2285 VMMDevReq_VideoAccelFlush);
2286
2287 if (RT_SUCCESS (rc))
2288 {
2289 pDevExt->u.primary.pvReqFlush = req;
2290 }
2291 else
2292 {
2293 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Rrc!!!\n", rc));
2294 }
2295 }
2296 }
2297 else
2298 {
2299 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Rrc!!!\n", rc));
2300 }
2301
2302 if (RT_SUCCESS(rc))
2303 {
2304 ULONG ulEnabled = 0;
2305
2306 /*
2307 * Tell host that VBVA status is changed.
2308 */
2309 VMMDevVideoAccelEnable *req = NULL;
2310
2311 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2312 sizeof (VMMDevVideoAccelEnable),
2313 VMMDevReq_VideoAccelEnable);
2314
2315 if (RT_SUCCESS(rc))
2316 {
2317 req->u32Enable = ulEnable;
2318 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2319 req->fu32Status = 0;
2320
2321 rc = VbglGRPerform (&req->header);
2322
2323 if (RT_SUCCESS(rc) && RT_SUCCESS(req->header.rc))
2324 {
2325 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
2326 {
2327 /*
2328 * Initialize the result information and VBVA memory.
2329 */
2330 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
2331 {
2332 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2333 pVbvaResult->pfnFlush = vboxVbvaFlush;
2334 pVbvaResult->pvFlush = pDevExt;
2335 ulEnabled = 1;
2336 }
2337 else
2338 {
2339 VideoPortZeroMemory(&pVbvaResult, sizeof(VBVAENABLERESULT));
2340 }
2341
2342 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
2343 }
2344 else
2345 {
2346 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
2347
2348 /* Disable VBVA for old hosts. */
2349 req->u32Enable = 0;
2350 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2351 req->fu32Status = 0;
2352
2353 VbglGRPerform (&req->header);
2354
2355 rc = VERR_NOT_SUPPORTED;
2356 }
2357 }
2358 else
2359 {
2360 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Rrc, VMMDev rc = %Rrc!!!\n", rc, req->header.rc));
2361
2362 if (RT_SUCCESS(rc))
2363 {
2364 rc = req->header.rc;
2365 }
2366 }
2367
2368 VbglGRFree (&req->header);
2369 }
2370 else
2371 {
2372 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Rrc!!!\n", rc));
2373 }
2374
2375 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
2376 }
2377
2378 return rc;
2379}
Note: See TracBrowser for help on using the repository browser.

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