VirtualBox

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

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

Shared memory host guest interface (HGSMI) for the graphics device: the windows guest video driver prototype code.

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