VirtualBox

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

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

Updates for guest desktop integration

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.0 KB
Line 
1/*
2 * VirtualBox Video miniport driver for NT/2k/XP
3 *
4 * Based on DDK sample code.
5 *
6 * Copyright (C) 2006-2007 innotek GmbH
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License 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 if (RequestPacket->InputBufferLength < sizeof(RTRECT))
1467 {
1468 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: output buffer too small: %d needed: %d!!!\n",
1469 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
1470 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1471 return FALSE;
1472 }
1473 }
1474
1475 default:
1476 dprintf(("VBoxVideo::VBoxVideoStartIO: unsupported %p, fn %d(0x%x)\n",
1477 RequestPacket->IoControlCode,
1478 (RequestPacket->IoControlCode >> 2) & 0xFFF,
1479 (RequestPacket->IoControlCode >> 2) & 0xFFF));
1480 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1481 return FALSE;
1482 }
1483
1484 if (Result)
1485 RequestPacket->StatusBlock->Status = NO_ERROR;
1486 else
1487 RequestPacket->StatusBlock->Information = 0;
1488
1489// dprintf(("VBoxVideo::VBoxVideoStartIO: completed\n"));
1490
1491 return TRUE;
1492}
1493
1494/**
1495 * VBoxVideoReset HW
1496 *
1497 * Resets the video hardware.
1498 */
1499BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
1500{
1501 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
1502
1503 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1504
1505 if (pDevExt->iDevice > 0)
1506 {
1507 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
1508 pDevExt->iDevice));
1509 return TRUE;
1510 }
1511
1512 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1513 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
1514
1515 if (pDevExt->pvReqFlush != NULL)
1516 {
1517 VbglGRFree ((VMMDevRequestHeader *)pDevExt->pvReqFlush);
1518 pDevExt->pvReqFlush = NULL;
1519 }
1520
1521 VbglTerminate ();
1522
1523 return TRUE;
1524}
1525
1526/**
1527 * VBoxVideoGetPowerState
1528 *
1529 * Queries whether the device can support the requested power state.
1530 */
1531VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
1532 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
1533{
1534 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
1535 return NO_ERROR;
1536}
1537
1538/**
1539 * VBoxVideoSetPowerState
1540 *
1541 * Sets the power state of the specified device
1542 */
1543VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
1544 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
1545{
1546 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
1547 return NO_ERROR;
1548}
1549
1550/**
1551 * VBoxVideoSetCurrentMode
1552 *
1553 * Sets the adapter to the specified operating mode.
1554 */
1555BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
1556 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
1557{
1558 PVIDEO_MODE_INFORMATION ModeInfo;
1559
1560 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
1561
1562 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
1563 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
1564 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
1565 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
1566
1567 if (DeviceExtension->iDevice > 0)
1568 {
1569 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
1570 DeviceExtension->iDevice));
1571 return TRUE;
1572 }
1573
1574 /* set the mode characteristics */
1575 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
1576 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenWidth);
1577 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
1578 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->VisScreenHeight);
1579 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
1580 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)ModeInfo->BitsPerPlane);
1581 /* enable the mode */
1582 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1583 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
1584 /** @todo read from the port to see if the mode switch was successful */
1585
1586 return TRUE;
1587}
1588
1589/*
1590 * VBoxVideoResetDevice
1591 *
1592 * Resets the video hardware to the default mode, to which it was initialized
1593 * at system boot.
1594 */
1595
1596BOOLEAN FASTCALL VBoxVideoResetDevice(
1597 PDEVICE_EXTENSION DeviceExtension,
1598 PSTATUS_BLOCK StatusBlock)
1599{
1600 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
1601
1602 if (DeviceExtension->iDevice > 0)
1603 {
1604 /* If the device is the secondary display, however, it is recommended that no action be taken. */
1605 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
1606 DeviceExtension->iDevice));
1607 return TRUE;
1608 }
1609
1610#if 0
1611 /* Don't disable the extended video mode. This would only switch the video mode
1612 * to <current width> x <current height> x 0 bpp which is not what we want. And
1613 * even worse, it causes an disturbing additional mode switch */
1614 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
1615 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
1616#endif
1617
1618 return TRUE;
1619}
1620
1621/**
1622 * VBoxVideoMapVideoMemory
1623 *
1624 * Maps the video hardware frame buffer and video RAM into the virtual address
1625 * space of the requestor.
1626 */
1627BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
1628 PVIDEO_MEMORY RequestedAddress,
1629 PVIDEO_MEMORY_INFORMATION MapInformation,
1630 PSTATUS_BLOCK StatusBlock)
1631{
1632 PHYSICAL_ADDRESS FrameBuffer;
1633 ULONG inIoSpace = 0;
1634 VP_STATUS Status;
1635
1636 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory\n"));
1637
1638 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
1639
1640 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
1641 MapInformation->VideoRamLength = DeviceExtension->ulMaxFrameBufferSize + VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
1642
1643 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
1644 &MapInformation->VideoRamLength, &inIoSpace,
1645 &MapInformation->VideoRamBase);
1646
1647 if (Status == NO_ERROR)
1648 {
1649 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
1650 MapInformation->FrameBufferLength =
1651 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
1652 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
1653 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
1654
1655 return TRUE;
1656 }
1657
1658 return FALSE;
1659}
1660
1661/**
1662 * VBoxVideoUnmapVideoMemory
1663 *
1664 * Releases a mapping between the virtual address space and the adapter's
1665 * frame buffer and video RAM.
1666 */
1667BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
1668 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
1669{
1670 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
1671 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
1672 return TRUE;
1673}
1674
1675/**
1676 * VBoxVideoQueryNumAvailModes
1677 *
1678 * Returns the number of video modes supported by the adapter and the size
1679 * in bytes of the video mode information, which can be used to allocate a
1680 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
1681 */
1682BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
1683 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
1684{
1685 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
1686 /* calculate the video modes table */
1687 VBoxBuildModesTable(DeviceExtension);
1688 Modes->NumModes = gNumVideoModes;
1689 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
1690 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
1691 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
1692 return TRUE;
1693}
1694
1695/**
1696 * VBoxVideoQueryAvailModes
1697 *
1698 * Returns information about each video mode supported by the adapter.
1699 */
1700BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
1701 PVIDEO_MODE_INFORMATION ReturnedModes,
1702 PSTATUS_BLOCK StatusBlock)
1703{
1704 ULONG Size;
1705
1706 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
1707
1708 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
1709 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
1710 StatusBlock->Information = Size;
1711
1712 return TRUE;
1713}
1714
1715/**
1716 * VBoxVideoQueryCurrentMode
1717 *
1718 * Returns information about current video mode.
1719 */
1720BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
1721 PVIDEO_MODE_INFORMATION VideoModeInfo,
1722 PSTATUS_BLOCK StatusBlock)
1723{
1724 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
1725
1726 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
1727 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
1728
1729 return TRUE;
1730}
1731
1732/*
1733 * VBoxVideoSetColorRegisters
1734 *
1735 * Sets the adapter's color registers to the specified RGB values. There
1736 * are code paths in this function, one generic and one for VGA compatible
1737 * controllers. The latter is needed for Bochs, where the generic one isn't
1738 * yet implemented.
1739 */
1740
1741BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
1742 PDEVICE_EXTENSION DeviceExtension,
1743 PVIDEO_CLUT ColorLookUpTable,
1744 PSTATUS_BLOCK StatusBlock)
1745{
1746 LONG Entry;
1747
1748 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
1749
1750 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
1751 return FALSE;
1752
1753 for (Entry = ColorLookUpTable->FirstEntry;
1754 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
1755 Entry++)
1756 {
1757 VideoPortWritePortUchar((PUCHAR)0x03c8, (UCHAR)Entry);
1758 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
1759 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
1760 VideoPortWritePortUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
1761 }
1762
1763 return TRUE;
1764}
1765
1766VP_STATUS VBoxVideoGetChildDescriptor(
1767 PVOID HwDeviceExtension,
1768 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
1769 PVIDEO_CHILD_TYPE VideoChildType,
1770 PUCHAR pChildDescriptor,
1771 PULONG pUId,
1772 PULONG pUnused)
1773{
1774 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
1775 HwDeviceExtension, ChildEnumInfo));
1776
1777 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
1778
1779 if (ChildEnumInfo->ChildIndex > 0)
1780 {
1781 if ( (ChildEnumInfo->ChildIndex == 1 && gNumDisplays == 0)
1782 || ((int)ChildEnumInfo->ChildIndex <= gNumDisplays)
1783 )
1784 {
1785 *VideoChildType = Monitor;
1786 *pUId = ChildEnumInfo->ChildIndex;
1787
1788 return VIDEO_ENUM_MORE_DEVICES;
1789 }
1790 }
1791
1792 return ERROR_NO_MORE_DEVICES;
1793}
1794
1795
1796static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
1797{
1798 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
1799 DEVICE_EXTENSION *pPrimaryDevExt = (DEVICE_EXTENSION *)(pDevExt? pDevExt->pvPrimaryExt: NULL);
1800
1801 if (pPrimaryDevExt)
1802 {
1803 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->pvReqFlush;
1804
1805 if (req)
1806 {
1807 int rc = VbglGRPerform (&req->header);
1808
1809 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
1810 {
1811 dprintf(("VBoxVideo::vbvaFlush: rc = %Vrc, VMMDev rc = %Vrc!!!\n", rc, req->header.rc));
1812 }
1813 }
1814 }
1815
1816 return;
1817}
1818
1819int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
1820{
1821 int rc = VINF_SUCCESS;
1822
1823 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
1824
1825 /*
1826 * Query the VMMDev memory pointer. There we need VBVAMemory.
1827 */
1828 VMMDevMemory *pVMMDevMemory = NULL;
1829
1830 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
1831
1832 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
1833
1834 if (pDevExt->iDevice > 0)
1835 {
1836 DEVICE_EXTENSION *pPrimaryDevExt = (DEVICE_EXTENSION *)pDevExt->pvPrimaryExt;
1837
1838 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
1839 pDevExt->iDevice));
1840
1841 if ( ulEnable
1842 && pPrimaryDevExt->ulVbvaEnabled)
1843 {
1844 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
1845 pVbvaResult->pfnFlush = vboxVbvaFlush;
1846 pVbvaResult->pvFlush = pDevExt;
1847 }
1848 else
1849 {
1850 VideoPortZeroMemory(&pVbvaResult, sizeof(VBVAENABLERESULT));
1851 }
1852
1853 return rc;
1854 }
1855
1856 if (VBOX_SUCCESS(rc))
1857 {
1858 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
1859 if (pDevExt->pvReqFlush == NULL)
1860 {
1861 VMMDevVideoAccelFlush *req = NULL;
1862
1863 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
1864 sizeof (VMMDevVideoAccelFlush),
1865 VMMDevReq_VideoAccelFlush);
1866
1867 if (VBOX_SUCCESS (rc))
1868 {
1869 pDevExt->pvReqFlush = req;
1870 }
1871 else
1872 {
1873 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Vrc!!!\n", rc));
1874 }
1875 }
1876 }
1877 else
1878 {
1879 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Vrc!!!\n", rc));
1880 }
1881
1882 if (VBOX_SUCCESS(rc))
1883 {
1884 ULONG ulEnabled = 0;
1885
1886 /*
1887 * Tell host that VBVA status is changed.
1888 */
1889 VMMDevVideoAccelEnable *req = NULL;
1890
1891 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
1892 sizeof (VMMDevVideoAccelEnable),
1893 VMMDevReq_VideoAccelEnable);
1894
1895 if (VBOX_SUCCESS(rc))
1896 {
1897 req->u32Enable = ulEnable;
1898 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
1899 req->fu32Status = 0;
1900
1901 rc = VbglGRPerform (&req->header);
1902
1903 if (VBOX_SUCCESS(rc) && VBOX_SUCCESS(req->header.rc))
1904 {
1905 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
1906 {
1907 /*
1908 * Initialize the result information and VBVA memory.
1909 */
1910 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
1911 {
1912 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
1913 pVbvaResult->pfnFlush = vboxVbvaFlush;
1914 pVbvaResult->pvFlush = pDevExt;
1915 ulEnabled = 1;
1916 }
1917 else
1918 {
1919 VideoPortZeroMemory(&pVbvaResult, sizeof(VBVAENABLERESULT));
1920 }
1921
1922 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
1923 }
1924 else
1925 {
1926 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
1927
1928 /* Disable VBVA for old hosts. */
1929 req->u32Enable = 0;
1930 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
1931 req->fu32Status = 0;
1932
1933 VbglGRPerform (&req->header);
1934
1935 rc = VERR_NOT_SUPPORTED;
1936 }
1937 }
1938 else
1939 {
1940 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Vrc, VMMDev rc = %Vrc!!!\n", rc, req->header.rc));
1941
1942 if (VBOX_SUCCESS(rc))
1943 {
1944 rc = req->header.rc;
1945 }
1946 }
1947
1948 VbglGRFree (&req->header);
1949 }
1950 else
1951 {
1952 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Vrc!!!\n", rc));
1953 }
1954
1955 pDevExt->ulVbvaEnabled = ulEnabled;
1956 }
1957
1958 return rc;
1959}
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