VirtualBox

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

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

video hw accel: interrupt support in guest video adapter & driver, NetFlt/Adp/win: get rid of alloca

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