VirtualBox

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

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

Additions/WINNT: made the graphics miniport driver set the graphics guest capability

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