VirtualBox

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

Last change on this file since 23926 was 23926, checked in by vboxsync, 15 years ago

Windows guest video driver: 800x600 is always a valid video mode.

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

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