VirtualBox

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

Last change on this file since 8155 was 8155, checked in by vboxsync, 16 years ago

The Big Sun Rebranding Header Change

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