VirtualBox

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

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

VBoxVideo: Logging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 91.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. */
732static void 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
784static int 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
815static void 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 /* Initialize VBoxGuest library */
1185 rc = VbglInit ();
1186
1187 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
1188
1189 /* Setup the Device Extension and if possible secondary displays. */
1190 VBoxSetupDisplays((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
1191
1192 // pretend success to make the driver work.
1193 rc = NO_ERROR;
1194 } else
1195 {
1196 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
1197 rc = ERROR_DEV_NOT_EXIST;
1198 }
1199 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
1200 return rc;
1201}
1202
1203/**
1204 * VBoxVideoInitialize
1205 *
1206 * Performs the first initialization of the adapter, after the HAL has given
1207 * up control of the video hardware to the video port driver.
1208 */
1209BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
1210{
1211 VP_STATUS status;
1212
1213 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
1214
1215 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1216
1217 /* Initialize the request pointer. */
1218 pDevExt->u.primary.pvReqFlush = NULL;
1219
1220 /*
1221 * Get the last custom resolution
1222 */
1223 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1224 L"CustomXRes",
1225 FALSE,
1226 VBoxRegistryCallback,
1227 &gCustomXRes);
1228 if (status != NO_ERROR)
1229 gCustomXRes = 0;
1230 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1231 L"CustomYRes",
1232 FALSE,
1233 VBoxRegistryCallback,
1234 &gCustomYRes);
1235 if (status != NO_ERROR)
1236 gCustomYRes = 0;
1237 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1238 L"CustomBPP",
1239 FALSE,
1240 VBoxRegistryCallback,
1241 &gCustomBPP);
1242 if (status != NO_ERROR)
1243 gCustomBPP = 0;
1244
1245 dprintf(("VBoxVideo: got stored custom resolution %dx%dx%d\n", gCustomXRes, gCustomYRes, gCustomBPP));
1246
1247 return TRUE;
1248}
1249
1250/**
1251 * VBoxVideoStartIO
1252 *
1253 * Processes the specified Video Request Packet.
1254 */
1255BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
1256 PVIDEO_REQUEST_PACKET RequestPacket)
1257{
1258 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1259
1260 BOOLEAN Result;
1261
1262// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
1263
1264 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1265
1266 switch (RequestPacket->IoControlCode)
1267 {
1268 case IOCTL_VIDEO_SET_CURRENT_MODE:
1269 {
1270 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
1271 {
1272 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1273 return TRUE;
1274 }
1275 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1276 (PVIDEO_MODE)RequestPacket->InputBuffer,
1277 RequestPacket->StatusBlock);
1278 break;
1279 }
1280
1281 case IOCTL_VIDEO_RESET_DEVICE:
1282 {
1283 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
1284 RequestPacket->StatusBlock);
1285 break;
1286 }
1287
1288 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
1289 {
1290 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
1291 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1292 {
1293 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1294 return TRUE;
1295 }
1296 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1297 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1298 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
1299 RequestPacket->StatusBlock);
1300 break;
1301 }
1302
1303 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
1304 {
1305 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1306 {
1307 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1308 return TRUE;
1309 }
1310 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1311 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1312 RequestPacket->StatusBlock);
1313 break;
1314 }
1315
1316 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
1317 {
1318 PVIDEO_SHARE_MEMORY pShareMemory;
1319 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
1320 PHYSICAL_ADDRESS shareAddress;
1321 PVOID virtualAddress = NULL;
1322 ULONG sharedViewSize;
1323 ULONG inIoSpace = 0;
1324 VP_STATUS status;
1325
1326 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
1327
1328 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
1329 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
1330
1331 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1332 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1333 Result = FALSE;
1334 break;
1335 }
1336
1337 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1338
1339 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
1340 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
1341
1342 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));
1343 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
1344 Result = FALSE;
1345 break;
1346 }
1347
1348 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
1349
1350 virtualAddress = pShareMemory->ProcessHandle;
1351 sharedViewSize = pShareMemory->ViewSize;
1352
1353 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
1354
1355 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
1356 if (status != NO_ERROR)
1357 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
1358 Result = (status == NO_ERROR);
1359
1360 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
1361 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
1362 pShareMemoryInformation->VirtualAddress = virtualAddress;
1363 pShareMemoryInformation->SharedViewSize = sharedViewSize;
1364 break;
1365 }
1366
1367 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
1368 {
1369 PVIDEO_SHARE_MEMORY pShareMemory;
1370 VP_STATUS status;
1371
1372 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
1373
1374 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
1375 {
1376 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1377 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1378 Result = FALSE;
1379 break;
1380 }
1381
1382 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1383
1384 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
1385 if (status != NO_ERROR)
1386 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
1387 Result = (status == NO_ERROR);
1388 break;
1389 }
1390
1391 /*
1392 * The display driver asks us how many video modes we support
1393 * so that it can supply an appropriate buffer for the next call.
1394 */
1395 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
1396 {
1397 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
1398 {
1399 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1400 return TRUE;
1401 }
1402 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1403 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
1404 RequestPacket->StatusBlock);
1405 break;
1406 }
1407
1408 /*
1409 * The display driver asks us to provide a list of supported video modes
1410 * into a buffer it has allocated.
1411 */
1412 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
1413 {
1414 if (RequestPacket->OutputBufferLength <
1415 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
1416 {
1417 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1418 return TRUE;
1419 }
1420 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1421 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1422 RequestPacket->StatusBlock);
1423 break;
1424 }
1425
1426 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
1427 {
1428 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
1429 RequestPacket->InputBufferLength <
1430 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
1431 sizeof(VIDEO_CLUT))
1432 {
1433 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1434 return TRUE;
1435 }
1436 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
1437 (PVIDEO_CLUT)RequestPacket->InputBuffer,
1438 RequestPacket->StatusBlock);
1439 break;
1440 }
1441
1442 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
1443 {
1444 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
1445 {
1446 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1447 return TRUE;
1448 }
1449 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1450 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1451 RequestPacket->StatusBlock);
1452 break;
1453 }
1454
1455 // show the pointer
1456 case IOCTL_VIDEO_ENABLE_POINTER:
1457 {
1458 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
1459 // find out whether the host wants absolute positioning
1460 if (vboxQueryHostWantsAbsolute())
1461 {
1462 // tell the host to use the guest's pointer
1463 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1464
1465 /* Visible and No Shape means Show the pointer.
1466 * It is enough to init only this field.
1467 */
1468 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
1469
1470 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
1471
1472 if (!Result)
1473 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
1474 } else
1475 {
1476 // fallback to software pointer
1477 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1478 Result = FALSE;
1479 }
1480 break;
1481 }
1482
1483 // hide the pointer
1484 case IOCTL_VIDEO_DISABLE_POINTER:
1485 {
1486 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
1487 // find out whether the host wants absolute positioning
1488 if (vboxQueryHostWantsAbsolute())
1489 {
1490 // tell the host to hide pointer
1491 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1492
1493 /* Enable == 0 means no shape, not visible.
1494 * It is enough to init only this field.
1495 */
1496 PointerAttributes.Enable = 0;
1497
1498 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
1499
1500 if (!Result)
1501 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
1502 } else
1503 {
1504 // fallback to software pointer
1505 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1506 Result = FALSE;
1507 }
1508 break;
1509 }
1510
1511 /*
1512 * Change the pointer shape
1513 */
1514 case IOCTL_VIDEO_SET_POINTER_ATTR:
1515 {
1516 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
1517 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
1518 {
1519 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
1520 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1521 return TRUE;
1522 }
1523 // find out whether the host wants absolute positioning
1524 if (vboxQueryHostWantsAbsolute())
1525 {
1526 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
1527#if 0
1528 dprintf(("Pointer shape information:\n"
1529 "\tFlags: %d\n"
1530 "\tWidth: %d\n"
1531 "\tHeight: %d\n"
1532 "\tWidthInBytes: %d\n"
1533 "\tEnable: %d\n"
1534 "\tColumn: %d\n"
1535 "\tRow: %d\n",
1536 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
1537 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
1538 pPointerAttributes->Row));
1539 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
1540#endif
1541 Result = vboxUpdatePointerShape(pPointerAttributes, RequestPacket->InputBufferLength);
1542 if (!Result)
1543 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
1544 } else
1545 {
1546 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
1547 // fallback to software pointer
1548 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1549 Result = FALSE;
1550 }
1551 break;
1552 }
1553
1554 // query pointer information
1555 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
1556 {
1557 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
1558 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1559 Result = FALSE;
1560 break;
1561 }
1562
1563 // set the pointer position
1564 case IOCTL_VIDEO_SET_POINTER_POSITION:
1565 {
1566 /// @todo There is an issue when we disable pointer integration.
1567 // The guest pointer will be invisible. We have to somehow cause
1568 // the pointer attributes to be set again. But how? The same holds
1569 // true for the opposite case where we get two pointers.
1570
1571 //dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_POSITION\n"));
1572 // find out whether the host wants absolute positioning
1573 if (vboxQueryHostWantsAbsolute())
1574 {
1575 // @todo we are supposed to show currently invisible pointer?
1576 Result = TRUE;
1577 } else
1578 {
1579 // fallback to software pointer
1580 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1581 Result = FALSE;
1582 }
1583 break;
1584 }
1585
1586 // query the pointer position
1587 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
1588 {
1589 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
1590 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
1591 {
1592 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
1593 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1594 return TRUE;
1595 }
1596 Result = FALSE;
1597 uint16_t mousePosX;
1598 uint16_t mousePosY;
1599 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
1600 {
1601 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
1602 PVIDEO_MODE_INFORMATION ModeInfo;
1603 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
1604 // map from 0xFFFF to the current resolution
1605 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
1606 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
1607 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
1608 Result = TRUE;
1609 }
1610 if (!Result)
1611 {
1612 // fallback to software pointer
1613 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1614 }
1615 break;
1616 }
1617
1618 // Determine hardware cursor capabilities. We will always report that we are
1619 // very capable even though the host might not want to do pointer integration.
1620 // This is done because we can still return errors on the actual calls later to
1621 // make the display driver go to the fallback routines.
1622 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
1623 {
1624 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
1625 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
1626 {
1627 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
1628 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1629 return TRUE;
1630 }
1631 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
1632 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
1633 VIDEO_MODE_COLOR_POINTER |
1634 VIDEO_MODE_MONO_POINTER;
1635 // for now we go with 64x64 cursors
1636 pCaps->MaxWidth = 64;
1637 pCaps->MaxHeight = 64;
1638 // that doesn't seem to be relevant, VBoxDisp doesn't use it
1639 pCaps->HWPtrBitmapStart = -1;
1640 pCaps->HWPtrBitmapEnd = -1;
1641 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
1642 Result = TRUE;
1643 break;
1644 }
1645
1646 /* Attach/detach DualView devices */
1647 case IOCTL_VIDEO_SWITCH_DUALVIEW:
1648 {
1649 ULONG ulAttach;
1650
1651 ulAttach = *((PULONG)RequestPacket->InputBuffer);
1652 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
1653
1654 if (pDevExt->iDevice > 0)
1655 {
1656 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
1657 }
1658 Result = TRUE;
1659 break;
1660 }
1661
1662 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
1663 {
1664 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
1665
1666 if (pDevExt->pPrimary->u.primary.bVBoxVideoSupported)
1667 {
1668 /* The display driver must have prepared the monitor information. */
1669 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1670 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE + pDevExt->iDevice);
1671 }
1672 else
1673 {
1674 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1675 }
1676 Result = pDevExt->pPrimary->u.primary.bVBoxVideoSupported;
1677 break;
1678 }
1679
1680 case IOCTL_VIDEO_QUERY_DISPLAY_INFO:
1681 {
1682 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_DISPLAY_INFO\n"));
1683
1684 if (RequestPacket->OutputBufferLength < sizeof(QUERYDISPLAYINFORESULT))
1685 {
1686 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
1687 RequestPacket->OutputBufferLength, sizeof(QUERYDISPLAYINFORESULT)));
1688 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1689 return FALSE;
1690 }
1691
1692 QUERYDISPLAYINFORESULT *pDispInfo = (QUERYDISPLAYINFORESULT *)RequestPacket->OutputBuffer;
1693
1694 pDispInfo->iDevice = pDevExt->iDevice;
1695 pDispInfo->u32DisplayInfoSize = pDevExt->pPrimary->u.primary.ulDisplayInformationSize;
1696
1697 RequestPacket->StatusBlock->Information = sizeof(QUERYDISPLAYINFORESULT);
1698 Result = TRUE;
1699
1700 break;
1701 }
1702
1703 case IOCTL_VIDEO_VBVA_ENABLE:
1704 {
1705 int rc;
1706 ULONG ulEnable;
1707
1708 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
1709
1710 if (RequestPacket->InputBufferLength < sizeof(ULONG))
1711 {
1712 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
1713 RequestPacket->InputBufferLength, sizeof(ULONG)));
1714 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1715 return FALSE;
1716 }
1717
1718 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
1719 {
1720 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
1721 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
1722 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1723 return FALSE;
1724 }
1725
1726 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
1727 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
1728
1729 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
1730 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Vrc\n", rc));
1731
1732 if (VBOX_FAILURE (rc))
1733 {
1734 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
1735 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1736 return FALSE;
1737 }
1738
1739 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
1740 Result = TRUE;
1741
1742 break;
1743 }
1744
1745 /* Private ioctls */
1746 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
1747 {
1748 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
1749 int rc;
1750
1751 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
1752 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
1753 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
1754 {
1755 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
1756 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
1757 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1758 return FALSE;
1759 }
1760 /*
1761 * Inform the host about the visible region
1762 */
1763 VMMDevVideoSetVisibleRegion *req = NULL;
1764
1765 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
1766 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
1767 VMMDevReq_VideoSetVisibleRegion);
1768
1769 if (VBOX_SUCCESS(rc))
1770 {
1771 req->cRect = cRect;
1772 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
1773
1774 rc = VbglGRPerform (&req->header);
1775
1776 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
1777 {
1778 Result = TRUE;
1779 break;
1780 }
1781 }
1782 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x (hdr.rc=%x)\n", rc, (req) ? req->header.rc : -1));
1783 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1784 return FALSE;
1785 }
1786
1787 default:
1788 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
1789 RequestPacket->IoControlCode,
1790 (RequestPacket->IoControlCode >> 2) & 0xFFF,
1791 (RequestPacket->IoControlCode >> 2) & 0xFFF));
1792 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1793 return FALSE;
1794 }
1795
1796 if (Result)
1797 RequestPacket->StatusBlock->Status = NO_ERROR;
1798 else
1799 RequestPacket->StatusBlock->Information = 0;
1800
1801// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
1802
1803 return TRUE;
1804}
1805
1806/**
1807 * VBoxVideoReset HW
1808 *
1809 * Resets the video hardware.
1810 */
1811BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
1812{
1813 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
1814
1815 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1816
1817 if (pDevExt->iDevice > 0)
1818 {
1819 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
1820 pDevExt->iDevice));
1821 return TRUE;
1822 }
1823
1824 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1825 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
1826
1827 if (pDevExt->u.primary.pvReqFlush != NULL)
1828 {
1829 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
1830 pDevExt->u.primary.pvReqFlush = NULL;
1831 }
1832
1833 VbglTerminate ();
1834
1835 vboxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvMiniportHeap);
1836 vboxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvAdapterInformation);
1837
1838 return TRUE;
1839}
1840
1841/**
1842 * VBoxVideoGetPowerState
1843 *
1844 * Queries whether the device can support the requested power state.
1845 */
1846VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
1847 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
1848{
1849 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
1850 return NO_ERROR;
1851}
1852
1853/**
1854 * VBoxVideoSetPowerState
1855 *
1856 * Sets the power state of the specified device
1857 */
1858VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
1859 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
1860{
1861 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
1862 return NO_ERROR;
1863}
1864
1865/**
1866 * VBoxVideoSetGraphicsCap
1867 *
1868 * Tells the host whether or not we currently support graphics in the
1869 * additions
1870 */
1871BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
1872{
1873 VMMDevReqGuestCapabilities2 *req = NULL;
1874 int rc;
1875
1876 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
1877 sizeof (VMMDevReqGuestCapabilities2),
1878 VMMDevReq_SetGuestCapabilities);
1879
1880 if (!RT_SUCCESS(rc))
1881 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
1882 else
1883 {
1884 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
1885 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
1886
1887 rc = VbglGRPerform (&req->header);
1888 if (!RT_SUCCESS(rc) || !RT_SUCCESS(req->header.rc))
1889 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc, VMMDev rc = %Rrc\n", rc, req->header.rc));
1890 if (RT_SUCCESS(rc))
1891 rc = req->header.rc;
1892 }
1893 if (req != NULL)
1894 VbglGRFree (&req->header);
1895 return RT_SUCCESS(rc);
1896}
1897
1898/**
1899 * VBoxVideoSetCurrentMode
1900 *
1901 * Sets the adapter to the specified operating mode.
1902 */
1903BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
1904 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
1905{
1906 PVIDEO_MODE_INFORMATION ModeInfo;
1907
1908 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
1909
1910 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
1911 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
1912 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
1913 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
1914
1915 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
1916 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
1917 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
1918
1919 if (DeviceExtension->iDevice > 0)
1920 {
1921 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
1922 DeviceExtension->iDevice));
1923 return TRUE;
1924 }
1925
1926 /* set the mode characteristics */
1927 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
1928 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenWidth);
1929 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
1930 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenHeight);
1931 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
1932 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->BitsPerPlane);
1933 /* enable the mode */
1934 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1935 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
1936 /** @todo read from the port to see if the mode switch was successful */
1937
1938 /* Tell the host that we now support graphics in the additions.
1939 * @todo: Keep old behaviour, because VBoxVideoResetDevice is called on every graphics
1940 * mode switch and causes an OFF/ON sequence which is not handled by frontends
1941 * (for example Qt GUI debug build asserts when seamless is being enabled).
1942 */
1943 // VBoxVideoSetGraphicsCap(TRUE);
1944 return TRUE;
1945}
1946
1947/*
1948 * VBoxVideoResetDevice
1949 *
1950 * Resets the video hardware to the default mode, to which it was initialized
1951 * at system boot.
1952 */
1953
1954BOOLEAN FASTCALL VBoxVideoResetDevice(
1955 PDEVICE_EXTENSION DeviceExtension,
1956 PSTATUS_BLOCK StatusBlock)
1957{
1958 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
1959
1960 if (DeviceExtension->iDevice > 0)
1961 {
1962 /* If the device is the secondary display, however, it is recommended that no action be taken. */
1963 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
1964 DeviceExtension->iDevice));
1965 return TRUE;
1966 }
1967
1968#if 0
1969 /* Don't disable the extended video mode. This would only switch the video mode
1970 * to <current width> x <current height> x 0 bpp which is not what we want. And
1971 * even worse, it causes an disturbing additional mode switch */
1972 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1973 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
1974#endif
1975
1976 /* Tell the host that we no longer support graphics in the additions
1977 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
1978 */
1979 // VBoxVideoSetGraphicsCap(FALSE);
1980 return TRUE;
1981}
1982
1983/**
1984 * VBoxVideoMapVideoMemory
1985 *
1986 * Maps the video hardware frame buffer and video RAM into the virtual address
1987 * space of the requestor.
1988 */
1989BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
1990 PVIDEO_MEMORY RequestedAddress,
1991 PVIDEO_MEMORY_INFORMATION MapInformation,
1992 PSTATUS_BLOCK StatusBlock)
1993{
1994 PHYSICAL_ADDRESS FrameBuffer;
1995 ULONG inIoSpace = 0;
1996 VP_STATUS Status;
1997
1998 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory\n"));
1999
2000 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
2001
2002 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
2003 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize
2004 + DeviceExtension->pPrimary->u.primary.ulDisplayInformationSize;
2005
2006 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
2007 &MapInformation->VideoRamLength, &inIoSpace,
2008 &MapInformation->VideoRamBase);
2009
2010 if (Status == NO_ERROR)
2011 {
2012 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
2013 MapInformation->FrameBufferLength =
2014 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
2015 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
2016 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
2017
2018 /* Save the new framebuffer size */
2019 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
2020 return TRUE;
2021 }
2022
2023 return FALSE;
2024}
2025
2026/**
2027 * VBoxVideoUnmapVideoMemory
2028 *
2029 * Releases a mapping between the virtual address space and the adapter's
2030 * frame buffer and video RAM.
2031 */
2032BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2033 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
2034{
2035 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
2036 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
2037 return TRUE;
2038}
2039
2040/**
2041 * VBoxVideoQueryNumAvailModes
2042 *
2043 * Returns the number of video modes supported by the adapter and the size
2044 * in bytes of the video mode information, which can be used to allocate a
2045 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
2046 */
2047BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
2048 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
2049{
2050 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
2051 /* calculate the video modes table */
2052 VBoxBuildModesTable(DeviceExtension);
2053 Modes->NumModes = gNumVideoModes;
2054 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
2055 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
2056 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
2057 return TRUE;
2058}
2059
2060/**
2061 * VBoxVideoQueryAvailModes
2062 *
2063 * Returns information about each video mode supported by the adapter.
2064 */
2065BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
2066 PVIDEO_MODE_INFORMATION ReturnedModes,
2067 PSTATUS_BLOCK StatusBlock)
2068{
2069 ULONG Size;
2070
2071 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
2072
2073 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
2074 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
2075 StatusBlock->Information = Size;
2076
2077 return TRUE;
2078}
2079
2080/**
2081 * VBoxVideoQueryCurrentMode
2082 *
2083 * Returns information about current video mode.
2084 */
2085BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2086 PVIDEO_MODE_INFORMATION VideoModeInfo,
2087 PSTATUS_BLOCK StatusBlock)
2088{
2089 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
2090
2091 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
2092 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
2093
2094 return TRUE;
2095}
2096
2097/*
2098 * VBoxVideoSetColorRegisters
2099 *
2100 * Sets the adapter's color registers to the specified RGB values. There
2101 * are code paths in this function, one generic and one for VGA compatible
2102 * controllers. The latter is needed for Bochs, where the generic one isn't
2103 * yet implemented.
2104 */
2105
2106BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
2107 PDEVICE_EXTENSION DeviceExtension,
2108 PVIDEO_CLUT ColorLookUpTable,
2109 PSTATUS_BLOCK StatusBlock)
2110{
2111 LONG Entry;
2112
2113 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
2114
2115 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
2116 return FALSE;
2117
2118 for (Entry = ColorLookUpTable->FirstEntry;
2119 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
2120 Entry++)
2121 {
2122 VideoPortWritePortUchar((PUCHAR)0x03c8, (UCHAR)Entry);
2123 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
2124 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
2125 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
2126 }
2127
2128 return TRUE;
2129}
2130
2131VP_STATUS VBoxVideoGetChildDescriptor(
2132 PVOID HwDeviceExtension,
2133 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
2134 PVIDEO_CHILD_TYPE VideoChildType,
2135 PUCHAR pChildDescriptor,
2136 PULONG pUId,
2137 PULONG pUnused)
2138{
2139 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
2140 HwDeviceExtension, ChildEnumInfo));
2141
2142 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
2143
2144 if (ChildEnumInfo->ChildIndex > 0)
2145 {
2146 if ((int)ChildEnumInfo->ChildIndex <= pDevExt->pPrimary->u.primary.cDisplays)
2147 {
2148 *VideoChildType = Monitor;
2149 *pUId = ChildEnumInfo->ChildIndex;
2150
2151 return VIDEO_ENUM_MORE_DEVICES;
2152 }
2153 }
2154
2155 return ERROR_NO_MORE_DEVICES;
2156}
2157
2158
2159static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
2160{
2161 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
2162 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
2163
2164 if (pPrimaryDevExt)
2165 {
2166 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
2167
2168 if (req)
2169 {
2170 int rc = VbglGRPerform (&req->header);
2171
2172 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
2173 {
2174 dprintf(("VBoxVideo::vbvaFlush: rc = %Vrc, VMMDev rc = %Vrc!!!\n", rc, req->header.rc));
2175 }
2176 }
2177 }
2178
2179 return;
2180}
2181
2182int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
2183{
2184 int rc = VINF_SUCCESS;
2185
2186 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
2187
2188 /*
2189 * Query the VMMDev memory pointer. There we need VBVAMemory.
2190 */
2191 VMMDevMemory *pVMMDevMemory = NULL;
2192
2193 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
2194
2195 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
2196
2197 if (pDevExt->iDevice > 0)
2198 {
2199 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
2200
2201 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
2202 pDevExt->iDevice));
2203
2204 if ( ulEnable
2205 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
2206 {
2207 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2208 pVbvaResult->pfnFlush = vboxVbvaFlush;
2209 pVbvaResult->pvFlush = pDevExt;
2210 }
2211 else
2212 {
2213 VideoPortZeroMemory(&pVbvaResult, sizeof(VBVAENABLERESULT));
2214 }
2215
2216 return rc;
2217 }
2218
2219 if (VBOX_SUCCESS(rc))
2220 {
2221 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
2222 if (pDevExt->u.primary.pvReqFlush == NULL)
2223 {
2224 VMMDevVideoAccelFlush *req = NULL;
2225
2226 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2227 sizeof (VMMDevVideoAccelFlush),
2228 VMMDevReq_VideoAccelFlush);
2229
2230 if (VBOX_SUCCESS (rc))
2231 {
2232 pDevExt->u.primary.pvReqFlush = req;
2233 }
2234 else
2235 {
2236 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Vrc!!!\n", rc));
2237 }
2238 }
2239 }
2240 else
2241 {
2242 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Vrc!!!\n", rc));
2243 }
2244
2245 if (VBOX_SUCCESS(rc))
2246 {
2247 ULONG ulEnabled = 0;
2248
2249 /*
2250 * Tell host that VBVA status is changed.
2251 */
2252 VMMDevVideoAccelEnable *req = NULL;
2253
2254 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2255 sizeof (VMMDevVideoAccelEnable),
2256 VMMDevReq_VideoAccelEnable);
2257
2258 if (VBOX_SUCCESS(rc))
2259 {
2260 req->u32Enable = ulEnable;
2261 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2262 req->fu32Status = 0;
2263
2264 rc = VbglGRPerform (&req->header);
2265
2266 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
2267 {
2268 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
2269 {
2270 /*
2271 * Initialize the result information and VBVA memory.
2272 */
2273 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
2274 {
2275 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2276 pVbvaResult->pfnFlush = vboxVbvaFlush;
2277 pVbvaResult->pvFlush = pDevExt;
2278 ulEnabled = 1;
2279 }
2280 else
2281 {
2282 VideoPortZeroMemory(&pVbvaResult, sizeof(VBVAENABLERESULT));
2283 }
2284
2285 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
2286 }
2287 else
2288 {
2289 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
2290
2291 /* Disable VBVA for old hosts. */
2292 req->u32Enable = 0;
2293 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2294 req->fu32Status = 0;
2295
2296 VbglGRPerform (&req->header);
2297
2298 rc = VERR_NOT_SUPPORTED;
2299 }
2300 }
2301 else
2302 {
2303 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Vrc, VMMDev rc = %Vrc!!!\n", rc, req->header.rc));
2304
2305 if (VBOX_SUCCESS(rc))
2306 {
2307 rc = req->header.rc;
2308 }
2309 }
2310
2311 VbglGRFree (&req->header);
2312 }
2313 else
2314 {
2315 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Vrc!!!\n", rc));
2316 }
2317
2318 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
2319 }
2320
2321 return rc;
2322}
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