VirtualBox

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

Last change on this file since 3558 was 3558, checked in by vboxsync, 18 years ago

Implemented IOCTL_VIDEO_VBOX_SETVISIBLEREGION

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

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