VirtualBox

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

Last change on this file since 4053 was 4053, checked in by vboxsync, 17 years ago

Use the generic VBoxVideo interface in Windows guest video driver.

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

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