VirtualBox

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

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

Added IOCTL_VIDEO_SHARE_VIDEO_MEMORY & IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 87.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
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,
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,
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,
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;
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->ulFrameBufferSize)
1302 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->ulFrameBufferSize) ) {
1303
1304 dprintf(("IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INVALID_PARAMETER\n"));
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 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1339 Result = FALSE;
1340 break;
1341 }
1342
1343 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1344
1345 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
1346 if (status != NO_ERROR)
1347 dprintf(("VideoPortUnmapMemory failed with %x\n", status));
1348 Result = (status == NO_ERROR);
1349 break;
1350 }
1351
1352 /*
1353 * The display driver asks us how many video modes we support
1354 * so that it can supply an appropriate buffer for the next call.
1355 */
1356 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
1357 {
1358 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
1359 {
1360 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1361 return TRUE;
1362 }
1363 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1364 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
1365 RequestPacket->StatusBlock);
1366 break;
1367 }
1368
1369 /*
1370 * The display driver asks us to provide a list of supported video modes
1371 * into a buffer it has allocated.
1372 */
1373 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
1374 {
1375 if (RequestPacket->OutputBufferLength <
1376 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
1377 {
1378 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1379 return TRUE;
1380 }
1381 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1382 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1383 RequestPacket->StatusBlock);
1384 break;
1385 }
1386
1387 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
1388 {
1389 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
1390 RequestPacket->InputBufferLength <
1391 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
1392 sizeof(VIDEO_CLUT))
1393 {
1394 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1395 return TRUE;
1396 }
1397 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
1398 (PVIDEO_CLUT)RequestPacket->InputBuffer,
1399 RequestPacket->StatusBlock);
1400 break;
1401 }
1402
1403 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
1404 {
1405 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
1406 {
1407 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1408 return TRUE;
1409 }
1410 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1411 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1412 RequestPacket->StatusBlock);
1413 break;
1414 }
1415
1416 // show the pointer
1417 case IOCTL_VIDEO_ENABLE_POINTER:
1418 {
1419 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
1420 // find out whether the host wants absolute positioning
1421 if (vboxQueryHostWantsAbsolute())
1422 {
1423 // tell the host to use the guest's pointer
1424 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1425
1426 /* Visible and No Shape means Show the pointer.
1427 * It is enough to init only this field.
1428 */
1429 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
1430
1431 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
1432
1433 if (!Result)
1434 dprintf(("VBoxVideo::VBoxVideoStartIO: could not hide hardware pointer -> fallback\n"));
1435 } else
1436 {
1437 // fallback to software pointer
1438 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1439 Result = FALSE;
1440 }
1441 break;
1442 }
1443
1444 // hide the pointer
1445 case IOCTL_VIDEO_DISABLE_POINTER:
1446 {
1447 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
1448 // find out whether the host wants absolute positioning
1449 if (vboxQueryHostWantsAbsolute())
1450 {
1451 // tell the host to hide pointer
1452 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1453
1454 /* Enable == 0 means no shape, not visible.
1455 * It is enough to init only this field.
1456 */
1457 PointerAttributes.Enable = 0;
1458
1459 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
1460
1461 if (!Result)
1462 dprintf(("VBoxVideo::VBoxVideoStartIO: could not hide hardware pointer -> fallback\n"));
1463 } else
1464 {
1465 // fallback to software pointer
1466 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1467 Result = FALSE;
1468 }
1469 break;
1470 }
1471
1472 /*
1473 * Change the pointer shape
1474 */
1475 case IOCTL_VIDEO_SET_POINTER_ATTR:
1476 {
1477 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
1478 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
1479 {
1480 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
1481 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1482 return TRUE;
1483 }
1484 // find out whether the host wants absolute positioning
1485 if (vboxQueryHostWantsAbsolute())
1486 {
1487 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
1488#if 0
1489 dprintf(("Pointer shape information:\n"
1490 "\tFlags: %d\n"
1491 "\tWidth: %d\n"
1492 "\tHeight: %d\n"
1493 "\tWidthInBytes: %d\n"
1494 "\tEnable: %d\n"
1495 "\tColumn: %d\n"
1496 "\tRow: %d\n",
1497 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
1498 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
1499 pPointerAttributes->Row));
1500 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
1501#endif
1502 Result = vboxUpdatePointerShape(pPointerAttributes, RequestPacket->InputBufferLength);
1503 if (!Result)
1504 dprintf(("VBoxVideo::VBoxVideoStartIO: could not set hardware pointer -> fallback\n"));
1505 } else
1506 {
1507 dprintf(("VBoxVideo::VBoxVideoStartIO: fallback to software pointer\n"));
1508 // fallback to software pointer
1509 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1510 Result = FALSE;
1511 }
1512 break;
1513 }
1514
1515 // query pointer information
1516 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
1517 {
1518 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
1519 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1520 Result = FALSE;
1521 break;
1522 }
1523
1524 // set the pointer position
1525 case IOCTL_VIDEO_SET_POINTER_POSITION:
1526 {
1527 /// @todo There is an issue when we disable pointer integration.
1528 // The guest pointer will be invisible. We have to somehow cause
1529 // the pointer attributes to be set again. But how? The same holds
1530 // true for the opposite case where we get two pointers.
1531
1532 //dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_POSITION\n"));
1533 // find out whether the host wants absolute positioning
1534 if (vboxQueryHostWantsAbsolute())
1535 {
1536 // @todo we are supposed to show currently invisible pointer?
1537 Result = TRUE;
1538 } else
1539 {
1540 // fallback to software pointer
1541 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1542 Result = FALSE;
1543 }
1544 break;
1545 }
1546
1547 // query the pointer position
1548 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
1549 {
1550 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
1551 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
1552 {
1553 dprintf(("VBoxVideo::VBoxVideoStartIO: output buffer too small!\n"));
1554 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1555 return TRUE;
1556 }
1557 Result = FALSE;
1558 uint16_t mousePosX;
1559 uint16_t mousePosY;
1560 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
1561 {
1562 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
1563 PVIDEO_MODE_INFORMATION ModeInfo;
1564 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
1565 // map from 0xFFFF to the current resolution
1566 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
1567 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
1568 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
1569 Result = TRUE;
1570 }
1571 if (!Result)
1572 {
1573 // fallback to software pointer
1574 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1575 }
1576 break;
1577 }
1578
1579 // Determine hardware cursor capabilities. We will always report that we are
1580 // very capable even though the host might not want to do pointer integration.
1581 // This is done because we can still return errors on the actual calls later to
1582 // make the display driver go to the fallback routines.
1583 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
1584 {
1585 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
1586 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
1587 {
1588 dprintf(("VBoxVideo::VBoxVideoStartIO: output buffer too small!\n"));
1589 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1590 return TRUE;
1591 }
1592 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
1593 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
1594 VIDEO_MODE_COLOR_POINTER |
1595 VIDEO_MODE_MONO_POINTER;
1596 // for now we go with 64x64 cursors
1597 pCaps->MaxWidth = 64;
1598 pCaps->MaxHeight = 64;
1599 // that doesn't seem to be relevant, VBoxDisp doesn't use it
1600 pCaps->HWPtrBitmapStart = -1;
1601 pCaps->HWPtrBitmapEnd = -1;
1602 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
1603 Result = TRUE;
1604 break;
1605 }
1606
1607 /* Attach/detach DualView devices */
1608 case IOCTL_VIDEO_SWITCH_DUALVIEW:
1609 {
1610 ULONG ulAttach;
1611
1612 ulAttach = *((PULONG)RequestPacket->InputBuffer);
1613 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
1614
1615 if (pDevExt->iDevice > 0)
1616 {
1617 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
1618 }
1619 Result = TRUE;
1620 break;
1621 }
1622
1623 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
1624 {
1625 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
1626
1627 if (pDevExt->pPrimary->u.primary.bVBoxVideoSupported)
1628 {
1629 /* The display driver must have prepared the monitor information. */
1630 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1631 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE + pDevExt->iDevice);
1632 }
1633 else
1634 {
1635 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1636 }
1637 Result = pDevExt->pPrimary->u.primary.bVBoxVideoSupported;
1638 break;
1639 }
1640
1641 case IOCTL_VIDEO_QUERY_DISPLAY_INFO:
1642 {
1643 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_DISPLAY_INFO\n"));
1644
1645 if (RequestPacket->OutputBufferLength < sizeof(QUERYDISPLAYINFORESULT))
1646 {
1647 dprintf(("VBoxVideo::VBoxVideoStartIO: output buffer too small: %d needed: %d!!!\n",
1648 RequestPacket->OutputBufferLength, sizeof(QUERYDISPLAYINFORESULT)));
1649 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1650 return FALSE;
1651 }
1652
1653 QUERYDISPLAYINFORESULT *pDispInfo = (QUERYDISPLAYINFORESULT *)RequestPacket->OutputBuffer;
1654
1655 pDispInfo->iDevice = pDevExt->iDevice;
1656 pDispInfo->u32DisplayInfoSize = pDevExt->pPrimary->u.primary.ulDisplayInformationSize;
1657
1658 RequestPacket->StatusBlock->Information = sizeof(QUERYDISPLAYINFORESULT);
1659 Result = TRUE;
1660
1661 break;
1662 }
1663
1664 case IOCTL_VIDEO_VBVA_ENABLE:
1665 {
1666 int rc;
1667 ULONG ulEnable;
1668
1669 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
1670
1671 if (RequestPacket->InputBufferLength < sizeof(ULONG))
1672 {
1673 dprintf(("VBoxVideo::VBoxVideoStartIO: input buffer too small: %d needed: %d!!!\n",
1674 RequestPacket->InputBufferLength, sizeof(ULONG)));
1675 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1676 return FALSE;
1677 }
1678
1679 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
1680 {
1681 dprintf(("VBoxVideo::VBoxVideoStartIO: output buffer too small: %d needed: %d!!!\n",
1682 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
1683 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1684 return FALSE;
1685 }
1686
1687 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
1688 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
1689
1690 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
1691 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Vrc\n", rc));
1692
1693 if (VBOX_FAILURE (rc))
1694 {
1695 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
1696 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1697 return FALSE;
1698 }
1699
1700 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
1701 Result = TRUE;
1702
1703 break;
1704 }
1705
1706 /* Private ioctls */
1707 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
1708 {
1709 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
1710 int rc;
1711
1712 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
1713 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
1714 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
1715 {
1716 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: output buffer too small: %d needed: %d!!!\n",
1717 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
1718 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1719 return FALSE;
1720 }
1721 /*
1722 * Inform the host about the visible region
1723 */
1724 VMMDevVideoSetVisibleRegion *req = NULL;
1725
1726 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
1727 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
1728 VMMDevReq_VideoSetVisibleRegion);
1729
1730 if (VBOX_SUCCESS(rc))
1731 {
1732 req->cRect = cRect;
1733 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
1734
1735 rc = VbglGRPerform (&req->header);
1736
1737 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
1738 {
1739 Result = TRUE;
1740 break;
1741 }
1742 }
1743 dprintf(("VBoxVideo: failed with rc=%x (hdr.rc=%x)\n", rc, (req) ? req->header.rc : -1));
1744 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1745 return FALSE;
1746 }
1747
1748 default:
1749 dprintf(("VBoxVideo::VBoxVideoStartIO: unsupported %p, fn %d(0x%x)\n",
1750 RequestPacket->IoControlCode,
1751 (RequestPacket->IoControlCode >> 2) & 0xFFF,
1752 (RequestPacket->IoControlCode >> 2) & 0xFFF));
1753 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1754 return FALSE;
1755 }
1756
1757 if (Result)
1758 RequestPacket->StatusBlock->Status = NO_ERROR;
1759 else
1760 RequestPacket->StatusBlock->Information = 0;
1761
1762// dprintf(("VBoxVideo::VBoxVideoStartIO: completed\n"));
1763
1764 return TRUE;
1765}
1766
1767/**
1768 * VBoxVideoReset HW
1769 *
1770 * Resets the video hardware.
1771 */
1772BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
1773{
1774 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
1775
1776 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1777
1778 if (pDevExt->iDevice > 0)
1779 {
1780 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
1781 pDevExt->iDevice));
1782 return TRUE;
1783 }
1784
1785 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1786 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
1787
1788 if (pDevExt->u.primary.pvReqFlush != NULL)
1789 {
1790 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
1791 pDevExt->u.primary.pvReqFlush = NULL;
1792 }
1793
1794 VbglTerminate ();
1795
1796 vboxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvMiniportHeap);
1797 vboxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvAdapterInformation);
1798
1799 return TRUE;
1800}
1801
1802/**
1803 * VBoxVideoGetPowerState
1804 *
1805 * Queries whether the device can support the requested power state.
1806 */
1807VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
1808 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
1809{
1810 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
1811 return NO_ERROR;
1812}
1813
1814/**
1815 * VBoxVideoSetPowerState
1816 *
1817 * Sets the power state of the specified device
1818 */
1819VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
1820 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
1821{
1822 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
1823 return NO_ERROR;
1824}
1825
1826/**
1827 * VBoxVideoSetCurrentMode
1828 *
1829 * Sets the adapter to the specified operating mode.
1830 */
1831BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
1832 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
1833{
1834 PVIDEO_MODE_INFORMATION ModeInfo;
1835
1836 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
1837
1838 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
1839 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
1840 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
1841 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
1842
1843 if (DeviceExtension->iDevice > 0)
1844 {
1845 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
1846 DeviceExtension->iDevice));
1847 return TRUE;
1848 }
1849
1850 /* set the mode characteristics */
1851 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
1852 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenWidth);
1853 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
1854 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenHeight);
1855 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
1856 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->BitsPerPlane);
1857 /* enable the mode */
1858 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1859 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
1860 /** @todo read from the port to see if the mode switch was successful */
1861
1862 return TRUE;
1863}
1864
1865/*
1866 * VBoxVideoResetDevice
1867 *
1868 * Resets the video hardware to the default mode, to which it was initialized
1869 * at system boot.
1870 */
1871
1872BOOLEAN FASTCALL VBoxVideoResetDevice(
1873 PDEVICE_EXTENSION DeviceExtension,
1874 PSTATUS_BLOCK StatusBlock)
1875{
1876 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
1877
1878 if (DeviceExtension->iDevice > 0)
1879 {
1880 /* If the device is the secondary display, however, it is recommended that no action be taken. */
1881 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
1882 DeviceExtension->iDevice));
1883 return TRUE;
1884 }
1885
1886#if 0
1887 /* Don't disable the extended video mode. This would only switch the video mode
1888 * to <current width> x <current height> x 0 bpp which is not what we want. And
1889 * even worse, it causes an disturbing additional mode switch */
1890 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1891 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
1892#endif
1893
1894 return TRUE;
1895}
1896
1897/**
1898 * VBoxVideoMapVideoMemory
1899 *
1900 * Maps the video hardware frame buffer and video RAM into the virtual address
1901 * space of the requestor.
1902 */
1903BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
1904 PVIDEO_MEMORY RequestedAddress,
1905 PVIDEO_MEMORY_INFORMATION MapInformation,
1906 PSTATUS_BLOCK StatusBlock)
1907{
1908 PHYSICAL_ADDRESS FrameBuffer;
1909 ULONG inIoSpace = 0;
1910 VP_STATUS Status;
1911
1912 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory\n"));
1913
1914 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
1915
1916 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
1917 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize
1918 + DeviceExtension->pPrimary->u.primary.ulDisplayInformationSize;
1919
1920 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
1921 &MapInformation->VideoRamLength, &inIoSpace,
1922 &MapInformation->VideoRamBase);
1923
1924 if (Status == NO_ERROR)
1925 {
1926 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
1927 MapInformation->FrameBufferLength =
1928 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
1929 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
1930 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
1931
1932 /* Save the new framebuffer size */
1933 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
1934 return TRUE;
1935 }
1936
1937 return FALSE;
1938}
1939
1940/**
1941 * VBoxVideoUnmapVideoMemory
1942 *
1943 * Releases a mapping between the virtual address space and the adapter's
1944 * frame buffer and video RAM.
1945 */
1946BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
1947 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
1948{
1949 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
1950 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
1951 return TRUE;
1952}
1953
1954/**
1955 * VBoxVideoQueryNumAvailModes
1956 *
1957 * Returns the number of video modes supported by the adapter and the size
1958 * in bytes of the video mode information, which can be used to allocate a
1959 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
1960 */
1961BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
1962 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
1963{
1964 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
1965 /* calculate the video modes table */
1966 VBoxBuildModesTable(DeviceExtension);
1967 Modes->NumModes = gNumVideoModes;
1968 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
1969 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
1970 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
1971 return TRUE;
1972}
1973
1974/**
1975 * VBoxVideoQueryAvailModes
1976 *
1977 * Returns information about each video mode supported by the adapter.
1978 */
1979BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
1980 PVIDEO_MODE_INFORMATION ReturnedModes,
1981 PSTATUS_BLOCK StatusBlock)
1982{
1983 ULONG Size;
1984
1985 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
1986
1987 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
1988 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
1989 StatusBlock->Information = Size;
1990
1991 return TRUE;
1992}
1993
1994/**
1995 * VBoxVideoQueryCurrentMode
1996 *
1997 * Returns information about current video mode.
1998 */
1999BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2000 PVIDEO_MODE_INFORMATION VideoModeInfo,
2001 PSTATUS_BLOCK StatusBlock)
2002{
2003 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
2004
2005 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
2006 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
2007
2008 return TRUE;
2009}
2010
2011/*
2012 * VBoxVideoSetColorRegisters
2013 *
2014 * Sets the adapter's color registers to the specified RGB values. There
2015 * are code paths in this function, one generic and one for VGA compatible
2016 * controllers. The latter is needed for Bochs, where the generic one isn't
2017 * yet implemented.
2018 */
2019
2020BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
2021 PDEVICE_EXTENSION DeviceExtension,
2022 PVIDEO_CLUT ColorLookUpTable,
2023 PSTATUS_BLOCK StatusBlock)
2024{
2025 LONG Entry;
2026
2027 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
2028
2029 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
2030 return FALSE;
2031
2032 for (Entry = ColorLookUpTable->FirstEntry;
2033 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
2034 Entry++)
2035 {
2036 VideoPortWritePortUchar((PUCHAR)0x03c8, (UCHAR)Entry);
2037 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
2038 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
2039 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
2040 }
2041
2042 return TRUE;
2043}
2044
2045VP_STATUS VBoxVideoGetChildDescriptor(
2046 PVOID HwDeviceExtension,
2047 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
2048 PVIDEO_CHILD_TYPE VideoChildType,
2049 PUCHAR pChildDescriptor,
2050 PULONG pUId,
2051 PULONG pUnused)
2052{
2053 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
2054 HwDeviceExtension, ChildEnumInfo));
2055
2056 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
2057
2058 if (ChildEnumInfo->ChildIndex > 0)
2059 {
2060 if ((int)ChildEnumInfo->ChildIndex <= pDevExt->pPrimary->u.primary.cDisplays)
2061 {
2062 *VideoChildType = Monitor;
2063 *pUId = ChildEnumInfo->ChildIndex;
2064
2065 return VIDEO_ENUM_MORE_DEVICES;
2066 }
2067 }
2068
2069 return ERROR_NO_MORE_DEVICES;
2070}
2071
2072
2073static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
2074{
2075 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
2076 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
2077
2078 if (pPrimaryDevExt)
2079 {
2080 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
2081
2082 if (req)
2083 {
2084 int rc = VbglGRPerform (&req->header);
2085
2086 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
2087 {
2088 dprintf(("VBoxVideo::vbvaFlush: rc = %Vrc, VMMDev rc = %Vrc!!!\n", rc, req->header.rc));
2089 }
2090 }
2091 }
2092
2093 return;
2094}
2095
2096int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
2097{
2098 int rc = VINF_SUCCESS;
2099
2100 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
2101
2102 /*
2103 * Query the VMMDev memory pointer. There we need VBVAMemory.
2104 */
2105 VMMDevMemory *pVMMDevMemory = NULL;
2106
2107 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
2108
2109 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
2110
2111 if (pDevExt->iDevice > 0)
2112 {
2113 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
2114
2115 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
2116 pDevExt->iDevice));
2117
2118 if ( ulEnable
2119 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
2120 {
2121 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2122 pVbvaResult->pfnFlush = vboxVbvaFlush;
2123 pVbvaResult->pvFlush = pDevExt;
2124 }
2125 else
2126 {
2127 VideoPortZeroMemory(&pVbvaResult, sizeof(VBVAENABLERESULT));
2128 }
2129
2130 return rc;
2131 }
2132
2133 if (VBOX_SUCCESS(rc))
2134 {
2135 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
2136 if (pDevExt->u.primary.pvReqFlush == NULL)
2137 {
2138 VMMDevVideoAccelFlush *req = NULL;
2139
2140 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2141 sizeof (VMMDevVideoAccelFlush),
2142 VMMDevReq_VideoAccelFlush);
2143
2144 if (VBOX_SUCCESS (rc))
2145 {
2146 pDevExt->u.primary.pvReqFlush = req;
2147 }
2148 else
2149 {
2150 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Vrc!!!\n", rc));
2151 }
2152 }
2153 }
2154 else
2155 {
2156 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Vrc!!!\n", rc));
2157 }
2158
2159 if (VBOX_SUCCESS(rc))
2160 {
2161 ULONG ulEnabled = 0;
2162
2163 /*
2164 * Tell host that VBVA status is changed.
2165 */
2166 VMMDevVideoAccelEnable *req = NULL;
2167
2168 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2169 sizeof (VMMDevVideoAccelEnable),
2170 VMMDevReq_VideoAccelEnable);
2171
2172 if (VBOX_SUCCESS(rc))
2173 {
2174 req->u32Enable = ulEnable;
2175 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2176 req->fu32Status = 0;
2177
2178 rc = VbglGRPerform (&req->header);
2179
2180 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
2181 {
2182 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
2183 {
2184 /*
2185 * Initialize the result information and VBVA memory.
2186 */
2187 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
2188 {
2189 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2190 pVbvaResult->pfnFlush = vboxVbvaFlush;
2191 pVbvaResult->pvFlush = pDevExt;
2192 ulEnabled = 1;
2193 }
2194 else
2195 {
2196 VideoPortZeroMemory(&pVbvaResult, sizeof(VBVAENABLERESULT));
2197 }
2198
2199 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
2200 }
2201 else
2202 {
2203 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
2204
2205 /* Disable VBVA for old hosts. */
2206 req->u32Enable = 0;
2207 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2208 req->fu32Status = 0;
2209
2210 VbglGRPerform (&req->header);
2211
2212 rc = VERR_NOT_SUPPORTED;
2213 }
2214 }
2215 else
2216 {
2217 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Vrc, VMMDev rc = %Vrc!!!\n", rc, req->header.rc));
2218
2219 if (VBOX_SUCCESS(rc))
2220 {
2221 rc = req->header.rc;
2222 }
2223 }
2224
2225 VbglGRFree (&req->header);
2226 }
2227 else
2228 {
2229 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Vrc!!!\n", rc));
2230 }
2231
2232 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
2233 }
2234
2235 return rc;
2236}
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