VirtualBox

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

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

The Giant CDDL Dual-License Header Change.

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