VirtualBox

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

Last change on this file since 33282 was 33264, checked in by vboxsync, 14 years ago

Additions/Win: Allow any horizontal resolution if graphics device supports it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 118.3 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 Oracle Corporation
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
17#include "VBoxVideo.h"
18#include "Helper.h"
19
20#include <iprt/log.h>
21#include <VBox/VMMDev.h>
22#include <VBox/VBoxGuest.h>
23#include <VBox/VBoxVideo.h>
24
25#include <VBox/VBoxGuestLib.h>
26#include <VBoxDisplay.h>
27
28#if _MSC_VER >= 1400 /* bird: MS fixed swprintf to be standard-conforming... */
29#define _INC_SWPRINTF_INL_
30extern "C" int __cdecl swprintf(wchar_t *, const wchar_t *, ...);
31#endif
32#include <wchar.h>
33
34#include "vboxioctl.h"
35
36
37static WCHAR VBoxChipType[] = L"VBOX";
38static WCHAR VBoxDACType[] = L"Integrated RAMDAC";
39static WCHAR VBoxAdapterString[] = L"VirtualBox Video Adapter";
40static WCHAR VBoxBiosString[] = L"Version 0xB0C2 or later";
41
42VIDEO_ACCESS_RANGE VGARanges[] = {
43 { 0x000003B0, 0x00000000, 0x0000000C, 1, 1, 1, 0 }, /* 0x3B0-0x3BB */
44 { 0x000003C0, 0x00000000, 0x00000020, 1, 1, 1, 0 }, /* 0x3C0-0x3DF */
45 { 0x000A0000, 0x00000000, 0x00020000, 0, 0, 1, 0 }, /* 0xA0000-0xBFFFF */
46};
47/*
48 * Globals for the last custom resolution set. This is important
49 * for system startup so that we report the last currently set
50 * custom resolution and Windows can use it again.
51 */
52#ifndef VBOX_WITH_MULTIMONITOR_FIX
53uint32_t gCustomXRes = 0;
54uint32_t gCustomYRes = 0;
55uint32_t gCustomBPP = 0;
56#endif /* !VBOX_WITH_MULTIMONITOR_FIX */
57
58int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult);
59
60#ifndef VBOX_WITH_WDDM
61ULONG DriverEntry(IN PVOID Context1, IN PVOID Context2)
62{
63 VIDEO_HW_INITIALIZATION_DATA InitData;
64 ULONG rc;
65
66 dprintf(("VBoxVideo::DriverEntry. Built %s %s\n", __DATE__, __TIME__));
67
68 VideoPortZeroMemory(&InitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));
69 InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
70 InitData.HwFindAdapter = VBoxVideoFindAdapter;
71 InitData.HwInitialize = VBoxVideoInitialize;
72#ifdef VBOX_WITH_VIDEOHWACCEL
73 InitData.HwInterrupt = VBoxVideoInterrupt;
74#else
75 InitData.HwInterrupt = NULL;
76#endif
77 InitData.HwStartIO = VBoxVideoStartIO;
78 InitData.HwResetHw = VBoxVideoResetHW;
79 InitData.HwDeviceExtensionSize = 0;
80 // nowhere documented but without the following line, NT4 SP0 will choke
81 InitData.AdapterInterfaceType = PCIBus;
82 InitData.HwGetPowerState = VBoxVideoGetPowerState;
83 InitData.HwSetPowerState = VBoxVideoSetPowerState;
84 InitData.HwGetVideoChildDescriptor = VBoxVideoGetChildDescriptor;
85 InitData.HwDeviceExtensionSize = sizeof(DEVICE_EXTENSION);
86 // report legacy VGA resource ranges
87 InitData.HwLegacyResourceList = VGARanges;
88 InitData.HwLegacyResourceCount = sizeof(VGARanges) / sizeof(VGARanges[0]);
89
90 // our DDK is at the Win2k3 level so we have to take special measures
91 // for backwards compatibility
92 switch (vboxQueryWinVersion())
93 {
94 case WINNT4:
95 dprintf(("VBoxVideo::DriverEntry: WINNT4\n"));
96 InitData.HwInitDataSize = SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA;
97 break;
98 case WIN2K:
99 dprintf(("VBoxVideo::DriverEntry: WIN2K\n"));
100 InitData.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
101 break;
102 }
103 rc = VideoPortInitialize(Context1, Context2, &InitData, NULL);
104
105 dprintf(("VBoxVideo::DriverEntry: returning with rc = 0x%x\n", rc));
106 return rc;
107}
108
109/*+++
110
111Routine Description:
112
113 This routine is used to read back various registry values.
114
115Arguments:
116
117 HwDeviceExtension
118 Supplies a pointer to the miniport's device extension.
119
120 Context
121 Context value passed to the get registry parameters routine.
122 If this is not null assume it's a ULONG* and save the data value in it.
123
124 ValueName
125 Name of the value requested.
126
127 ValueData
128 Pointer to the requested data.
129
130 ValueLength
131 Length of the requested data.
132
133Return Value:
134
135 If the variable doesn't exist return an error,
136 else if a context is supplied assume it's a PULONG and fill in the value
137 and return no error, else if the value is non-zero return an error.
138
139---*/
140VP_STATUS VBoxRegistryCallback(PVOID HwDeviceExtension, PVOID Context,
141 PWSTR ValueName, PVOID ValueData, ULONG ValueLength)
142{
143 //dprintf(("VBoxVideo::VBoxRegistryCallback: Context: %p, ValueName: %S, ValueData: %p, ValueLength: %d\n",
144 // Context, ValueName, ValueData, ValueLength));
145 if (ValueLength)
146 {
147 if (Context)
148 *(ULONG *)Context = *(PULONG)ValueData;
149 else if (*((PULONG)ValueData) != 0)
150 return ERROR_INVALID_PARAMETER;
151 return NO_ERROR;
152 }
153 else
154 return ERROR_INVALID_PARAMETER;
155}
156
157VP_STATUS VBoxVideoCmnRegQueryDword(IN VBOXCMNREG Reg, PWSTR pName, uint32_t *pVal)
158{
159 return VideoPortGetRegistryParameters(Reg, pName, FALSE, VBoxRegistryCallback, pVal);
160}
161
162VP_STATUS VBoxVideoCmnRegSetDword(IN VBOXCMNREG Reg, PWSTR pName, uint32_t Val)
163{
164 return VideoPortSetRegistryParameters(Reg, pName, &Val, sizeof(Val));
165}
166
167#endif /* #ifndef VBOX_WITH_WDDM */
168
169/*
170 * Global list of supported standard video modes. It will be
171 * filled dynamically.
172 */
173#define MAX_VIDEO_MODES 128
174#ifndef VBOX_WITH_MULTIMONITOR_FIX
175static VIDEO_MODE_INFORMATION VideoModes[MAX_VIDEO_MODES + 2] = { 0 };
176#else
177/*
178 * Additional space is reserved for custom video modes for 64 guest monitors.
179 * The custom video mode index is alternating and 2 indexes are reserved for the last custom mode.
180 */
181static VIDEO_MODE_INFORMATION VideoModes[MAX_VIDEO_MODES + 64 + 2] = { 0 };
182/* On the driver startup this is initialized from registry (replaces gCustom*). */
183static VIDEO_MODE_INFORMATION CustomVideoModes[64] = { 0 };
184#endif /* VBOX_WITH_MULTIMONITOR_FIX */
185/* number of available video modes, set by VBoxBuildModesTable */
186static uint32_t gNumVideoModes = 0;
187
188#ifdef VBOX_WITH_MULTIMONITOR_FIX
189static void initVideoModeInformation(VIDEO_MODE_INFORMATION *pVideoMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index, ULONG yoffset)
190{
191 /*
192 * Build mode entry.
193 */
194 memset(pVideoMode, 0, sizeof(VIDEO_MODE_INFORMATION));
195
196 pVideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
197 pVideoMode->ModeIndex = index;
198 pVideoMode->VisScreenWidth = xres;
199 pVideoMode->VisScreenHeight = yres - yoffset;
200 pVideoMode->ScreenStride = xres * ((bpp + 7) / 8);
201 pVideoMode->NumberOfPlanes = 1;
202 pVideoMode->BitsPerPlane = bpp;
203 pVideoMode->Frequency = 60;
204 pVideoMode->XMillimeter = 320;
205 pVideoMode->YMillimeter = 240;
206 switch (bpp)
207 {
208#ifdef VBOX_WITH_8BPP_MODES
209 case 8:
210 pVideoMode->NumberRedBits = 6;
211 pVideoMode->NumberGreenBits = 6;
212 pVideoMode->NumberBlueBits = 6;
213 pVideoMode->RedMask = 0;
214 pVideoMode->GreenMask = 0;
215 pVideoMode->BlueMask = 0;
216 break;
217#endif
218 case 16:
219 pVideoMode->NumberRedBits = 5;
220 pVideoMode->NumberGreenBits = 6;
221 pVideoMode->NumberBlueBits = 5;
222 pVideoMode->RedMask = 0xF800;
223 pVideoMode->GreenMask = 0x7E0;
224 pVideoMode->BlueMask = 0x1F;
225 break;
226 case 24:
227 pVideoMode->NumberRedBits = 8;
228 pVideoMode->NumberGreenBits = 8;
229 pVideoMode->NumberBlueBits = 8;
230 pVideoMode->RedMask = 0xFF0000;
231 pVideoMode->GreenMask = 0xFF00;
232 pVideoMode->BlueMask = 0xFF;
233 break;
234 case 32:
235 pVideoMode->NumberRedBits = 8;
236 pVideoMode->NumberGreenBits = 8;
237 pVideoMode->NumberBlueBits = 8;
238 pVideoMode->RedMask = 0xFF0000;
239 pVideoMode->GreenMask = 0xFF00;
240 pVideoMode->BlueMask = 0xFF;
241 break;
242 }
243 pVideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
244#ifdef VBOX_WITH_8BPP_MODES
245 if (bpp == 8)
246 pVideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
247#endif
248 pVideoMode->VideoMemoryBitmapWidth = xres;
249 pVideoMode->VideoMemoryBitmapHeight = yres - yoffset;
250 pVideoMode->DriverSpecificAttributeFlags = 0;
251}
252#endif /* VBOX_WITH_MULTIMONITOR_FIX */
253
254#ifdef VBOX_WITH_WDDM
255/* preferred mode index */
256static uint32_t gPreferredVideoMode = 0;
257
258static D3DKMDT_2DREGION g_VBoxWddmVideoResolutions[RT_ELEMENTS(VideoModes)];
259static uint32_t g_VBoxWddmNumResolutions;
260
261DECLINLINE(int) vboxWddmRectComparator(const D3DKMDT_2DREGION *pReg1, const D3DKMDT_2DREGION *pReg2)
262{
263 int tmp = pReg1->cx - pReg2->cx;
264 if(tmp)
265 return tmp;
266 tmp = pReg1->cy - pReg2->cy;
267 return tmp;
268}
269
270/* builds a g_VBoxWddmVideoResolutions given VideoModes info */
271VOID vboxWddmBuildResolutionTable()
272{
273 g_VBoxWddmNumResolutions = 0;
274
275 /* we don't care about the efficiency at this time */
276 for (uint32_t i = 0; i < gNumVideoModes; ++i)
277 {
278 VIDEO_MODE_INFORMATION *pMode = &VideoModes[i];
279 bool bFound = false;
280 for (uint32_t j = 0; j < g_VBoxWddmNumResolutions; ++j)
281 {
282 if (g_VBoxWddmVideoResolutions[j].cx == pMode->VisScreenWidth
283 && g_VBoxWddmVideoResolutions[j].cy == pMode->VisScreenHeight)
284 {
285 bFound = true;
286 break;
287 }
288 }
289
290 if (!bFound)
291 {
292 Assert(g_VBoxWddmNumResolutions < RT_ELEMENTS(g_VBoxWddmVideoResolutions));
293 g_VBoxWddmVideoResolutions[g_VBoxWddmNumResolutions].cx = pMode->VisScreenWidth;
294 g_VBoxWddmVideoResolutions[g_VBoxWddmNumResolutions].cy = pMode->VisScreenHeight;
295 ++g_VBoxWddmNumResolutions;
296 }
297 }
298}
299#endif
300
301static uint32_t g_xresNoVRAM = 0, g_yresNoVRAM = 0, g_bppNoVRAM = 0;
302
303/**
304 * Helper function to dynamically build our table of standard video
305 * modes. We take the amount of VRAM and create modes with standard
306 * geometries until we've either reached the maximum number of modes
307 * or the available VRAM does not allow for additional modes.
308 */
309VOID VBoxBuildModesTable(PDEVICE_EXTENSION DeviceExtension)
310{
311 /* we need this static counter to always have a new mode index for our */
312 /* custom video mode, otherwise Windows thinks there is no mode switch */
313 static int gInvocationCounter = 0;
314
315 VBOXCMNREG Reg;
316 VBoxVideoCmnRegInit(DeviceExtension, &Reg);
317
318 /* the resolution matrix */
319 struct
320 {
321 uint16_t xRes;
322 uint16_t yRes;
323 } resolutionMatrix[] =
324 {
325 /* standard modes */
326 { 640, 480 },
327 { 800, 600 },
328 { 1024, 768 },
329 { 1152, 864 },
330 { 1280, 960 },
331 { 1280, 1024 },
332 { 1400, 1050 },
333 { 1600, 1200 },
334 { 1920, 1440 },
335#ifndef VBOX_WITH_WDDM
336 /* multi screen modes with 1280x1024 */
337 { 2560, 1024 },
338 { 3840, 1024 },
339 { 5120, 1024 },
340 /* multi screen modes with 1600x1200 */
341 { 3200, 1200 },
342 { 4800, 1200 },
343 { 6400, 1200 },
344#endif
345 };
346 size_t matrixSize = sizeof(resolutionMatrix) / sizeof(resolutionMatrix[0]);
347
348 /* there are 4 color depths: 8, 16, 24 and 32bpp and we reserve 50% of the modes for other sources */
349 size_t maxModesPerColorDepth = MAX_VIDEO_MODES / 2 / 4;
350
351 /* size of the VRAM in bytes */
352
353#ifndef VBOX_WITH_WDDM
354 ULONG vramSize = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
355#else
356 ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(DeviceExtension);
357#ifndef VBOXWDDM_RENDER_FROM_SHADOW
358 /* at least two surfaces will be needed: primary & shadow */
359 vramSize /= 2;
360#endif
361
362 gPreferredVideoMode = 0;
363#endif
364
365 gNumVideoModes = 0;
366
367 size_t numModesCurrentColorDepth;
368 size_t matrixIndex;
369 VP_STATUS status = 0;
370
371 /* Always add 800x600 video modes. Windows XP+ needs at least 800x600 resolution
372 * and fallbacks to 800x600x4bpp VGA mode if the driver did not report suitable modes.
373 * This resolution could be rejected by a low resolution host (netbooks, etc).
374 */
375 int cBytesPerPixel;
376 for (cBytesPerPixel = 1; cBytesPerPixel <= 4; cBytesPerPixel++)
377 {
378 int cBitsPerPixel = cBytesPerPixel * 8; /* 8, 16, 24, 32 */
379
380#ifndef VBOX_WITH_8BPP_MODES
381 if (cBitsPerPixel == 8)
382 {
383 continue;
384 }
385#endif /* !VBOX_WITH_8BPP_MODES */
386
387 /* does the mode fit into the VRAM? */
388 if (800 * 600 * cBytesPerPixel > (LONG)vramSize)
389 {
390 continue;
391 }
392
393 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
394 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
395 VideoModes[gNumVideoModes].VisScreenWidth = 800;
396 VideoModes[gNumVideoModes].VisScreenHeight = 600;
397 VideoModes[gNumVideoModes].ScreenStride = 800 * cBytesPerPixel;
398 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
399 VideoModes[gNumVideoModes].BitsPerPlane = cBitsPerPixel;
400 VideoModes[gNumVideoModes].Frequency = 60;
401 VideoModes[gNumVideoModes].XMillimeter = 320;
402 VideoModes[gNumVideoModes].YMillimeter = 240;
403 switch (cBytesPerPixel)
404 {
405 case 1:
406 {
407 VideoModes[gNumVideoModes].NumberRedBits = 6;
408 VideoModes[gNumVideoModes].NumberGreenBits = 6;
409 VideoModes[gNumVideoModes].NumberBlueBits = 6;
410 VideoModes[gNumVideoModes].RedMask = 0;
411 VideoModes[gNumVideoModes].GreenMask = 0;
412 VideoModes[gNumVideoModes].BlueMask = 0;
413 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
414 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
415 } break;
416 case 2:
417 {
418 VideoModes[gNumVideoModes].NumberRedBits = 5;
419 VideoModes[gNumVideoModes].NumberGreenBits = 6;
420 VideoModes[gNumVideoModes].NumberBlueBits = 5;
421 VideoModes[gNumVideoModes].RedMask = 0xF800;
422 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
423 VideoModes[gNumVideoModes].BlueMask = 0x1F;
424 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
425 } break;
426 case 3:
427 {
428 VideoModes[gNumVideoModes].NumberRedBits = 8;
429 VideoModes[gNumVideoModes].NumberGreenBits = 8;
430 VideoModes[gNumVideoModes].NumberBlueBits = 8;
431 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
432 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
433 VideoModes[gNumVideoModes].BlueMask = 0xFF;
434 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
435 } break;
436 default:
437 case 4:
438 {
439 VideoModes[gNumVideoModes].NumberRedBits = 8;
440 VideoModes[gNumVideoModes].NumberGreenBits = 8;
441 VideoModes[gNumVideoModes].NumberBlueBits = 8;
442 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
443 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
444 VideoModes[gNumVideoModes].BlueMask = 0xFF;
445 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
446#ifdef VBOX_WITH_WDDM
447 gPreferredVideoMode = gNumVideoModes;
448#endif
449 } break;
450 }
451 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = 800;
452 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = 600;
453 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
454
455 /* a new mode has been filled in */
456 ++gNumVideoModes;
457 }
458
459 /*
460 * Query the y-offset from the host
461 */
462 ULONG yOffset = vboxGetHeightReduction();
463
464#ifdef VBOX_WITH_8BPP_MODES
465 /*
466 * 8 bit video modes
467 */
468 numModesCurrentColorDepth = 0;
469 matrixIndex = 0;
470 while (numModesCurrentColorDepth < maxModesPerColorDepth)
471 {
472 /* are there any modes left in the matrix? */
473 if (matrixIndex >= matrixSize)
474 break;
475
476 /* does the mode fit into the VRAM? */
477 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 1 > (LONG)vramSize)
478 {
479 ++matrixIndex;
480 continue;
481 }
482
483 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
484 {
485 /* This mode was already added. */
486 ++matrixIndex;
487 continue;
488 }
489
490 /* does the host like that mode? */
491#ifndef VBOX_WITH_WDDM
492 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 8))
493#else
494 if (!vboxLikesVideoMode(0 /* @todo: */, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 8))
495#endif
496 {
497 ++matrixIndex;
498 continue;
499 }
500
501 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
502 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
503 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
504 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
505 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 1;
506 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
507 VideoModes[gNumVideoModes].BitsPerPlane = 8;
508 VideoModes[gNumVideoModes].Frequency = 60;
509 VideoModes[gNumVideoModes].XMillimeter = 320;
510 VideoModes[gNumVideoModes].YMillimeter = 240;
511 VideoModes[gNumVideoModes].NumberRedBits = 6;
512 VideoModes[gNumVideoModes].NumberGreenBits = 6;
513 VideoModes[gNumVideoModes].NumberBlueBits = 6;
514 VideoModes[gNumVideoModes].RedMask = 0;
515 VideoModes[gNumVideoModes].GreenMask = 0;
516 VideoModes[gNumVideoModes].BlueMask = 0;
517 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
518 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
519 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
520 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
521 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
522
523 /* a new mode has been filled in */
524 ++gNumVideoModes;
525 ++numModesCurrentColorDepth;
526 /* advance to the next mode matrix entry */
527 ++matrixIndex;
528 }
529#endif /* VBOX_WITH_8BPP_MODES */
530
531 /*
532 * 16 bit video modes
533 */
534 numModesCurrentColorDepth = 0;
535 matrixIndex = 0;
536 while (numModesCurrentColorDepth < maxModesPerColorDepth)
537 {
538 /* are there any modes left in the matrix? */
539 if (matrixIndex >= matrixSize)
540 break;
541
542 /* does the mode fit into the VRAM? */
543 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 2 > (LONG)vramSize)
544 {
545 ++matrixIndex;
546 continue;
547 }
548
549 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
550 {
551 /* This mode was already added. */
552 ++matrixIndex;
553 continue;
554 }
555
556 /* does the host like that mode? */
557#ifndef VBOX_WITH_WDDM
558 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 16))
559#else
560 if (!vboxLikesVideoMode(0 /* @todo: */, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 16))
561#endif
562
563 {
564 ++matrixIndex;
565 continue;
566 }
567
568 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
569 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
570 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
571 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
572 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 2;
573 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
574 VideoModes[gNumVideoModes].BitsPerPlane = 16;
575 VideoModes[gNumVideoModes].Frequency = 60;
576 VideoModes[gNumVideoModes].XMillimeter = 320;
577 VideoModes[gNumVideoModes].YMillimeter = 240;
578 VideoModes[gNumVideoModes].NumberRedBits = 5;
579 VideoModes[gNumVideoModes].NumberGreenBits = 6;
580 VideoModes[gNumVideoModes].NumberBlueBits = 5;
581 VideoModes[gNumVideoModes].RedMask = 0xF800;
582 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
583 VideoModes[gNumVideoModes].BlueMask = 0x1F;
584 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
585 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
586 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
587 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
588
589 /* a new mode has been filled in */
590 ++gNumVideoModes;
591 ++numModesCurrentColorDepth;
592 /* advance to the next mode matrix entry */
593 ++matrixIndex;
594 }
595
596 /*
597 * 24 bit video modes
598 */
599 numModesCurrentColorDepth = 0;
600 matrixIndex = 0;
601 while (numModesCurrentColorDepth < maxModesPerColorDepth)
602 {
603 /* are there any modes left in the matrix? */
604 if (matrixIndex >= matrixSize)
605 break;
606
607 /* does the mode fit into the VRAM? */
608 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 3 > (LONG)vramSize)
609 {
610 ++matrixIndex;
611 continue;
612 }
613
614 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
615 {
616 /* This mode was already added. */
617 ++matrixIndex;
618 continue;
619 }
620
621 /* does the host like that mode? */
622#ifndef VBOX_WITH_WDDM
623 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 24))
624#else
625 if (!vboxLikesVideoMode(0, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 24))
626#endif
627 {
628 ++matrixIndex;
629 continue;
630 }
631
632 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
633 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
634 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
635 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
636 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 3;
637 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
638 VideoModes[gNumVideoModes].BitsPerPlane = 24;
639 VideoModes[gNumVideoModes].Frequency = 60;
640 VideoModes[gNumVideoModes].XMillimeter = 320;
641 VideoModes[gNumVideoModes].YMillimeter = 240;
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 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
649 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
650 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
651 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
652
653 /* a new mode has been filled in */
654 ++gNumVideoModes;
655 ++numModesCurrentColorDepth;
656 /* advance to the next mode matrix entry */
657 ++matrixIndex;
658 }
659
660 /*
661 * 32 bit video modes
662 */
663 numModesCurrentColorDepth = 0;
664 matrixIndex = 0;
665 while (numModesCurrentColorDepth < maxModesPerColorDepth)
666 {
667 /* are there any modes left in the matrix? */
668 if (matrixIndex >= matrixSize)
669 break;
670
671 /* does the mode fit into the VRAM? */
672 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 4 > (LONG)vramSize)
673 {
674 ++matrixIndex;
675 continue;
676 }
677
678 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
679 {
680 /* This mode was already added. */
681 ++matrixIndex;
682 continue;
683 }
684
685 /* does the host like that mode? */
686#ifndef VBOX_WITH_WDDM
687 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 32))
688#else
689 if (!vboxLikesVideoMode(0, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 32))
690#endif
691 {
692 ++matrixIndex;
693 continue;
694 }
695
696 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
697 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
698 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
699 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
700 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 4;
701 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
702 VideoModes[gNumVideoModes].BitsPerPlane = 32;
703 VideoModes[gNumVideoModes].Frequency = 60;
704 VideoModes[gNumVideoModes].XMillimeter = 320;
705 VideoModes[gNumVideoModes].YMillimeter = 240;
706 VideoModes[gNumVideoModes].NumberRedBits = 8;
707 VideoModes[gNumVideoModes].NumberGreenBits = 8;
708 VideoModes[gNumVideoModes].NumberBlueBits = 8;
709 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
710 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
711 VideoModes[gNumVideoModes].BlueMask = 0xFF;
712 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
713 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
714 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
715 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
716
717 /* a new mode has been filled in */
718 ++gNumVideoModes;
719 ++numModesCurrentColorDepth;
720 /* advance to the next mode matrix entry */
721 ++matrixIndex;
722 }
723
724 /*
725 * Next, check the registry for additional modes
726 */
727 int curKeyNo = 0;
728#ifdef VBOX_WITH_WDDM
729 int fPreferredSet = 0;
730#endif
731 do
732 {
733 /* check if there is space in the mode list */
734 if (gNumVideoModes >= MAX_VIDEO_MODES)
735 break;
736
737 wchar_t keyname[24];
738 uint32_t xres, yres, bpp = 0;
739 swprintf(keyname, L"CustomMode%dWidth", curKeyNo);
740 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &xres);
741 /* upon the first error, we give up */
742 if (status != NO_ERROR)
743 break;
744 swprintf(keyname, L"CustomMode%dHeight", curKeyNo);
745 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &yres);
746 /* upon the first error, we give up */
747 if (status != NO_ERROR)
748 break;
749 swprintf(keyname, L"CustomMode%dBPP", curKeyNo);
750 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &bpp);
751 /* upon the first error, we give up */
752 if (status != NO_ERROR)
753 break;
754
755 dprintf(("VBoxVideo: custom mode %u returned: xres = %u, yres = %u, bpp = %u\n",
756 curKeyNo, xres, yres, bpp));
757
758 /* first test: do the values make sense? */
759 if ( (xres > (1 << 16))
760 || (yres > (1 << 16))
761 || ( (bpp != 16)
762 && (bpp != 24)
763 && (bpp != 32)))
764 break;
765
766 /* round down width to be a multiple of 8 if necessary */
767 if (!DeviceExtension->fAnyX)
768 xres &= 0xFFF8;
769
770 /* second test: does it fit within our VRAM? */
771 if (xres * yres * (bpp / 8) > vramSize)
772 break;
773
774 /* third test: does the host like the video mode? */
775#ifndef VBOX_WITH_WDDM
776 if (!vboxLikesVideoMode(DeviceExtension->iDevice, xres, yres, bpp))
777#else
778 if (!vboxLikesVideoMode(0, xres, yres, bpp))
779#endif
780 break;
781
782 dprintf(("VBoxVideo: adding mode from registry: xres = %d, yres = %d, bpp = %d\n", xres, yres, bpp));
783
784#ifdef VBOX_WITH_WDDM
785 if (!fPreferredSet)
786 {
787 gPreferredVideoMode = gNumVideoModes;
788 fPreferredSet = 1;
789 }
790#endif
791 /*
792 * Build mode entry.
793 * Note that we have to apply the y offset for the custom mode.
794 */
795 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
796 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
797 VideoModes[gNumVideoModes].VisScreenWidth = xres;
798 VideoModes[gNumVideoModes].VisScreenHeight = yres - yOffset;
799 VideoModes[gNumVideoModes].ScreenStride = xres * (bpp / 8);
800 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
801 VideoModes[gNumVideoModes].BitsPerPlane = bpp;
802 VideoModes[gNumVideoModes].Frequency = 60;
803 VideoModes[gNumVideoModes].XMillimeter = 320;
804 VideoModes[gNumVideoModes].YMillimeter = 240;
805 switch (bpp)
806 {
807 case 16:
808 VideoModes[gNumVideoModes].NumberRedBits = 5;
809 VideoModes[gNumVideoModes].NumberGreenBits = 6;
810 VideoModes[gNumVideoModes].NumberBlueBits = 5;
811 VideoModes[gNumVideoModes].RedMask = 0xF800;
812 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
813 VideoModes[gNumVideoModes].BlueMask = 0x1F;
814 break;
815 case 24:
816 VideoModes[gNumVideoModes].NumberRedBits = 8;
817 VideoModes[gNumVideoModes].NumberGreenBits = 8;
818 VideoModes[gNumVideoModes].NumberBlueBits = 8;
819 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
820 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
821 VideoModes[gNumVideoModes].BlueMask = 0xFF;
822 break;
823 case 32:
824 VideoModes[gNumVideoModes].NumberRedBits = 8;
825 VideoModes[gNumVideoModes].NumberGreenBits = 8;
826 VideoModes[gNumVideoModes].NumberBlueBits = 8;
827 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
828 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
829 VideoModes[gNumVideoModes].BlueMask = 0xFF;
830#ifdef VBOX_WITH_WDDM
831 /* 32-bit mode is more preferable, select it if not yet */
832 if (fPreferredSet < 2)
833 {
834 gPreferredVideoMode = gNumVideoModes;
835 fPreferredSet = 2;
836 }
837#endif
838 break;
839 }
840 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
841 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = xres;
842 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = yres - yOffset;
843 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
844 ++gNumVideoModes;
845
846 /* next run */
847 curKeyNo++;
848 /* only support 128 modes for now */
849 if (curKeyNo >= 128)
850 break;
851
852 } while(1);
853
854 /*
855 * Now we ask the host for a display change request. If there's one,
856 * this will be appended as a special mode so that it can be used by
857 * the Additions service process. The mode table is guaranteed to have
858 * two spare entries for this mode (alternating index thus 2).
859 *
860 * ... or ...
861 *
862 * Also we check if we got an user-stored custom resolution in the adapter
863 * registry key add it to the modes table.
864 */
865
866#ifdef VBOX_WITH_MULTIMONITOR_FIX
867 /* Add custom resolutions for each display and then for the display change request, if exists.
868 */
869 BOOLEAN fDisplayChangeRequest = FALSE;
870
871 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
872 if ( vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
873 && (xres || yres || bpp))
874 {
875 /* There is a pending display change request. */
876 fDisplayChangeRequest = TRUE;
877 }
878 if (display > RT_ELEMENTS(CustomVideoModes))
879 {
880 display = RT_ELEMENTS(CustomVideoModes) - 1;
881 }
882
883 dprintf(("display = %d, DeviceExtension->iDevice = %d\n", display, DeviceExtension->iDevice));
884 if (display != DeviceExtension->iDevice)
885 {
886 /* No need to go through the custom mode logic. And no need to clear the custom mode
887 * entry in the next 'for' loop.
888 */
889 fDisplayChangeRequest = FALSE;
890 }
891
892 dprintf(("VBoxVideo: fDisplayChangeRequest = %d\n", fDisplayChangeRequest));
893
894 /*
895 * Reinsert custom video modes for all displays.
896 */
897 int iCustomMode;
898 for (iCustomMode = 0; iCustomMode < commonFromDeviceExt(DeviceExtension)->cDisplays; iCustomMode++)
899 {
900 if (fDisplayChangeRequest && iCustomMode == display)
901 {
902 /* Do not keep info for this display, which received a video mode hint, to make sure that
903 * the new mode will be taken from the alternating index entries actually.
904 */
905 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
906 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
907 }
908 else
909 {
910 VideoModes[gNumVideoModes] = CustomVideoModes[iCustomMode];
911 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
912 }
913#ifdef LOG_ENABLED
914 dprintf(("Custom mode for %2d: %4d x %4d @ %2d\n",
915 iCustomMode, CustomVideoModes[iCustomMode].VisScreenWidth,
916 CustomVideoModes[iCustomMode].VisScreenHeight, CustomVideoModes[iCustomMode].BitsPerPlane));
917#endif
918 gNumVideoModes++;
919 }
920
921 if (display != DeviceExtension->iDevice)
922 {
923 /* The display change is for another monitor. Just add 2 standard modes to the table
924 * to make enough entries. This is not necessary if it is a first mode set (CurrentMode == 0),
925 * because these 2 entries will be added by "if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)"
926 * code branch.
927 */
928 if (DeviceExtension->CurrentMode != 0)
929 {
930 dprintf(("Filling custom mode entries.\n"));
931 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
932 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
933 gNumVideoModes++;
934 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
935 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
936 gNumVideoModes++;
937 }
938 }
939#endif /* VBOX_WITH_MULTIMONITOR_FIX */
940
941#ifndef VBOX_WITH_MULTIMONITOR_FIX
942 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
943 if ( ( vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
944 && (xres || yres || bpp))
945 || (gCustomXRes || gCustomYRes || gCustomBPP))
946#else
947 if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)
948#endif /* VBOX_WITH_MULTIMONITOR_FIX */
949 {
950#ifndef VBOX_WITH_WDDM
951 dprintf(("VBoxVideo: adding custom video mode as #%d, current mode: %d \n", gNumVideoModes + 1, DeviceExtension->CurrentMode));
952 /* handle the startup case */
953 if (DeviceExtension->CurrentMode == 0)
954#else
955 if (!commonFromDeviceExt(DeviceExtension)->cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
956#endif
957 {
958 /* Use the stored custom resolution values only if nothing was read from host.
959 * The custom mode might be not valid anymore and would block any hints from host.
960 */
961#ifndef VBOX_WITH_MULTIMONITOR_FIX
962 if (!xres)
963 xres = gCustomXRes;
964 if (!yres)
965 yres = gCustomYRes;
966 if (!bpp)
967 bpp = gCustomBPP;
968 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d\n", xres, yres, bpp));
969#else
970 if (!xres)
971 xres = CustomVideoModes[DeviceExtension->iDevice].VisScreenWidth;
972 if (!yres)
973 yres = CustomVideoModes[DeviceExtension->iDevice].VisScreenHeight;
974 if (!bpp)
975 bpp = CustomVideoModes[DeviceExtension->iDevice].BitsPerPlane;
976 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d for %d\n", xres, yres, bpp, DeviceExtension->iDevice));
977#endif /* VBOX_WITH_MULTIMONITOR_FIX */
978 }
979 /* round down to multiple of 8 if necessary */
980 if (!DeviceExtension->fAnyX) {
981 if ((xres & 0xfff8) != xres)
982 dprintf(("VBoxVideo: rounding down xres from %d to %d\n", xres, xres & 0xfff8));
983 xres &= 0xfff8;
984 }
985 /* take the current values for the fields that are not set */
986#ifndef VBOX_WITH_WDDM
987 if (DeviceExtension->CurrentMode != 0)
988 {
989 if (!xres)
990 xres = DeviceExtension->CurrentModeWidth;
991 if (!yres)
992 yres = DeviceExtension->CurrentModeHeight;
993 if (!bpp)
994 bpp = DeviceExtension->CurrentModeBPP;
995 }
996#else
997 if (commonFromDeviceExt(DeviceExtension)->cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
998 {
999 if (!xres)
1000 xres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.width;
1001 if (!yres)
1002 yres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.height;
1003 if (!bpp)
1004 bpp = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.bpp;
1005 }
1006#endif
1007
1008 /* Use a default value. */
1009 if (!bpp)
1010 bpp = 32;
1011
1012 /* does the host like that mode? */
1013#ifndef VBOX_WITH_WDDM
1014 if (vboxLikesVideoMode(DeviceExtension->iDevice, xres, yres, bpp))
1015#else
1016 if (vboxLikesVideoMode(0, xres, yres, bpp))
1017#endif
1018 {
1019 /* we must have a valid video mode by now and it must fit within the VRAM */
1020 if ( ( xres
1021 && yres
1022 && ( (bpp == 16)
1023#ifdef VBOX_WITH_8BPP_MODES
1024 || (bpp == 8)
1025#endif
1026 || (bpp == 24)
1027 || (bpp == 32)))
1028 && (xres * yres * (bpp / 8) < vramSize))
1029
1030 {
1031 /* we need an alternating index */
1032#ifdef VBOX_WITH_MULTIMONITOR_FIX
1033 /* Only alternate index if the new custom mode differs from the last one
1034 * (only resolution and bpp changes are important, a display change does not matter).
1035 * Always add 2 last entries to the mode array, so number of video modes
1036 * do not change.
1037 */
1038 BOOLEAN fNewInvocation = FALSE;
1039 static uint32_t sPrev_xres = 0;
1040 static uint32_t sPrev_yres = 0;
1041 static uint32_t sPrev_bpp = 0;
1042 if ( sPrev_xres != xres
1043 || sPrev_yres != yres
1044 || sPrev_bpp != bpp)
1045 {
1046 sPrev_xres = xres;
1047 sPrev_yres = yres;
1048 sPrev_bpp = bpp;
1049 fNewInvocation = TRUE;
1050 }
1051 BOOLEAN fAlternatedIndex = FALSE;
1052#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1053#ifndef VBOX_WITH_WDDM
1054 if (DeviceExtension->CurrentMode != 0)
1055#else
1056 if (commonFromDeviceExt(DeviceExtension)->cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
1057#endif
1058#ifndef VBOX_WITH_MULTIMONITOR_FIX
1059 {
1060 if (gInvocationCounter % 2)
1061 gNumVideoModes++;
1062 gInvocationCounter++;
1063 }
1064#else
1065 {
1066 if (fNewInvocation)
1067 gInvocationCounter++;
1068 if (gInvocationCounter % 2)
1069 {
1070 fAlternatedIndex = TRUE;
1071
1072 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
1073 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1074 gNumVideoModes++;
1075 }
1076 }
1077 else
1078 {
1079 fNewInvocation = FALSE;
1080 }
1081#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1082
1083 dprintf(("VBoxVideo: setting special mode to xres = %d, yres = %d, bpp = %d, display = %d\n", xres, yres, bpp, display));
1084#ifdef VBOX_WITH_MULTIMONITOR_FIX
1085 dprintf(("VBoxVideo: fNewInvocation = %d, fAlternatedIndex = %d\n", fNewInvocation, fAlternatedIndex));
1086#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1087#ifdef VBOX_WITH_WDDM
1088 /* assign host-supplied as the most preferable */
1089 gPreferredVideoMode = gNumVideoModes;
1090#endif
1091 /*
1092 * Build mode entry.
1093 * Note that we do not apply the y offset for the custom mode. It is
1094 * only used for the predefined modes that the user can configure in
1095 * the display properties dialog.
1096 */
1097 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1098 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1099 VideoModes[gNumVideoModes].VisScreenWidth = xres;
1100 VideoModes[gNumVideoModes].VisScreenHeight = yres;
1101 VideoModes[gNumVideoModes].ScreenStride = xres * (bpp / 8);
1102 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1103 VideoModes[gNumVideoModes].BitsPerPlane = bpp;
1104 VideoModes[gNumVideoModes].Frequency = 60;
1105 VideoModes[gNumVideoModes].XMillimeter = 320;
1106 VideoModes[gNumVideoModes].YMillimeter = 240;
1107 switch (bpp)
1108 {
1109#ifdef VBOX_WITH_8BPP_MODES
1110 case 8:
1111 VideoModes[gNumVideoModes].NumberRedBits = 6;
1112 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1113 VideoModes[gNumVideoModes].NumberBlueBits = 6;
1114 VideoModes[gNumVideoModes].RedMask = 0;
1115 VideoModes[gNumVideoModes].GreenMask = 0;
1116 VideoModes[gNumVideoModes].BlueMask = 0;
1117 break;
1118#endif
1119 case 16:
1120 VideoModes[gNumVideoModes].NumberRedBits = 5;
1121 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1122 VideoModes[gNumVideoModes].NumberBlueBits = 5;
1123 VideoModes[gNumVideoModes].RedMask = 0xF800;
1124 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
1125 VideoModes[gNumVideoModes].BlueMask = 0x1F;
1126 break;
1127 case 24:
1128 VideoModes[gNumVideoModes].NumberRedBits = 8;
1129 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1130 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1131 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1132 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1133 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1134 break;
1135 case 32:
1136 VideoModes[gNumVideoModes].NumberRedBits = 8;
1137 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1138 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1139 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1140 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1141 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1142 break;
1143 }
1144 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1145#ifdef VBOX_WITH_8BPP_MODES
1146 if (bpp == 8)
1147 VideoModes[gNumVideoModes].AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
1148#endif
1149 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = xres;
1150 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = yres;
1151 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
1152#ifdef VBOX_WITH_MULTIMONITOR_FIX
1153 /* Save the mode in the list of custom modes for this display. */
1154 CustomVideoModes[DeviceExtension->iDevice] = VideoModes[gNumVideoModes];
1155#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1156 ++gNumVideoModes;
1157
1158 /* for the startup case, we need this mode twice due to the alternating mode number */
1159#ifndef VBOX_WITH_WDDM
1160 if (DeviceExtension->CurrentMode == 0)
1161#else
1162 if (!commonFromDeviceExt(DeviceExtension)->cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
1163#endif
1164 {
1165 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
1166 memcpy(&VideoModes[gNumVideoModes], &VideoModes[gNumVideoModes - 1], sizeof(VIDEO_MODE_INFORMATION));
1167 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1168 gNumVideoModes++;
1169 }
1170#ifdef VBOX_WITH_MULTIMONITOR_FIX
1171 else if (!fAlternatedIndex)
1172 {
1173 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
1174 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
1175 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1176 gNumVideoModes++;
1177 }
1178#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1179
1180#ifndef VBOX_WITH_MULTIMONITOR_FIX
1181 /* store this video mode as the last custom video mode */
1182 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
1183 if (status != NO_ERROR)
1184 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
1185 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
1186 if (status != NO_ERROR)
1187 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
1188 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
1189 if (status != NO_ERROR)
1190 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
1191#else
1192 /* Save the custom mode for this display. */
1193 if (DeviceExtension->iDevice == 0)
1194 {
1195 /* Name without a suffix */
1196 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
1197 if (status != NO_ERROR)
1198 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
1199 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
1200 if (status != NO_ERROR)
1201 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
1202 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
1203 if (status != NO_ERROR)
1204 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
1205 }
1206 else
1207 {
1208 wchar_t keyname[32];
1209 swprintf(keyname, L"CustomXRes%d", DeviceExtension->iDevice);
1210 status = VBoxVideoCmnRegSetDword(Reg, keyname, xres);
1211 if (status != NO_ERROR)
1212 dprintf(("VBoxVideo: error %d writing CustomXRes%d\n", status, DeviceExtension->iDevice));
1213 swprintf(keyname, L"CustomYRes%d", DeviceExtension->iDevice);
1214 status = VBoxVideoCmnRegSetDword(Reg, keyname, yres);
1215 if (status != NO_ERROR)
1216 dprintf(("VBoxVideo: error %d writing CustomYRes%d\n", status, DeviceExtension->iDevice));
1217 swprintf(keyname, L"CustomBPP%d", DeviceExtension->iDevice);
1218 status = VBoxVideoCmnRegSetDword(Reg, keyname, bpp);
1219 if (status != NO_ERROR)
1220 dprintf(("VBoxVideo: error %d writing CustomBPP%d\n", status, DeviceExtension->iDevice));
1221 }
1222#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1223 }
1224 else
1225 {
1226 dprintf(("VBoxVideo: invalid parameters for special mode: (xres = %d, yres = %d, bpp = %d, vramSize = %d)\n",
1227 xres, yres, bpp, vramSize));
1228 if (xres * yres * (bpp / 8) >= vramSize
1229 && (xres != g_xresNoVRAM || yres != g_yresNoVRAM || bpp != g_bppNoVRAM))
1230 {
1231 LogRel(("VBoxVideo: not enough VRAM for video mode %dx%dx%dbpp. Available: %d bytes. Required: more than %d bytes.\n",
1232 xres, yres, bpp, vramSize, xres * yres * (bpp / 8)));
1233 g_xresNoVRAM = xres;
1234 g_yresNoVRAM = yres;
1235 g_bppNoVRAM = bpp;
1236 }
1237 }
1238 }
1239 else
1240 dprintf(("VBoxVideo: host does not like special mode: (xres = %d, yres = %d, bpp = %d)\n",
1241 xres, yres, bpp));
1242 }
1243#if defined(LOG_ENABLED)
1244 {
1245 int i;
1246#ifndef VBOX_WITH_WDDM
1247 dprintf(("VBoxVideo: VideoModes (CurrentMode = %d, last #%d)\n", DeviceExtension->CurrentMode, gNumVideoModes));
1248#endif
1249 for (i = 0; i < RT_ELEMENTS(VideoModes); i++)
1250 {
1251 if ( VideoModes[i].VisScreenWidth
1252 || VideoModes[i].VisScreenHeight
1253 || VideoModes[i].BitsPerPlane)
1254 {
1255 dprintf((" %2d: #%d %4d x %4d @ %2d\n",
1256 i, VideoModes[i].ModeIndex, VideoModes[i].VisScreenWidth,
1257 VideoModes[i].VisScreenHeight, VideoModes[i].BitsPerPlane));
1258 }
1259 }
1260 }
1261#endif
1262
1263#ifdef VBOX_WITH_WDDM
1264 vboxWddmBuildResolutionTable();
1265#endif
1266
1267 VBoxVideoCmnRegFini(Reg);
1268}
1269
1270#ifdef VBOX_WITH_WDDM
1271static bool g_bModesTableInitialized = false;
1272/**
1273 * Helper function to dynamically build our table of standard video
1274 * modes. We take the amount of VRAM and create modes with standard
1275 * geometries until we've either reached the maximum number of modes
1276 * or the available VRAM does not allow for additional modes.
1277 */
1278VOID VBoxWddmGetModesTable(PDEVICE_EXTENSION DeviceExtension, bool bRebuildTable,
1279 VIDEO_MODE_INFORMATION ** ppModes, uint32_t * pcModes, int32_t * pPreferrableMode,
1280 D3DKMDT_2DREGION **ppResolutions, uint32_t * pcResolutions)
1281{
1282 if(bRebuildTable || !g_bModesTableInitialized)
1283 {
1284 VBoxBuildModesTable(DeviceExtension);
1285 g_bModesTableInitialized = true;
1286 }
1287
1288 *ppModes = VideoModes;
1289 *pcModes = gNumVideoModes;
1290 *pPreferrableMode = (int32_t)gPreferredVideoMode;
1291 *ppResolutions = g_VBoxWddmVideoResolutions;
1292 *pcResolutions = g_VBoxWddmNumResolutions;
1293}
1294
1295VOID VBoxWddmInvalidateModesTable(PDEVICE_EXTENSION DeviceExtension)
1296{
1297 g_bModesTableInitialized = false;
1298}
1299
1300NTSTATUS VBoxWddmGetModesForResolution(PDEVICE_EXTENSION DeviceExtension, bool bRebuildTable,
1301 D3DKMDT_2DREGION *pResolution,
1302 VIDEO_MODE_INFORMATION * pModes, uint32_t cModes, uint32_t *pcModes, int32_t *piPreferrableMode)
1303{
1304 VIDEO_MODE_INFORMATION *pAllModes;
1305 uint32_t cAllModes, cAllResolutions;
1306 int32_t iPreferrableMode;
1307 D3DKMDT_2DREGION *pAllResolutions;
1308 VBoxWddmGetModesTable(DeviceExtension, bRebuildTable,
1309 &pAllModes, &cAllModes, &iPreferrableMode,
1310 &pAllResolutions, &cAllResolutions);
1311 NTSTATUS Status = STATUS_SUCCESS;
1312 uint32_t cFound = 0;
1313 int iFoundPreferrableMode = -1;
1314 for (uint32_t i = 0; i < cAllModes; ++i)
1315 {
1316 VIDEO_MODE_INFORMATION *pCur = &pAllModes[i];
1317 if (pResolution->cx == pAllModes[i].VisScreenWidth
1318 && pResolution->cy == pAllModes[i].VisScreenHeight)
1319 {
1320 if (pModes && cModes > cFound)
1321 memcpy(&pModes[cFound], pCur, sizeof (VIDEO_MODE_INFORMATION));
1322 else
1323 Status = STATUS_BUFFER_TOO_SMALL;
1324
1325 if (i == (uint32_t)iPreferrableMode)
1326 iFoundPreferrableMode = cFound;
1327
1328 ++cFound;
1329 }
1330 }
1331
1332 Assert(iFoundPreferrableMode < 0 || cFound > (uint32_t)iFoundPreferrableMode);
1333
1334 *pcModes = cFound;
1335 if (piPreferrableMode)
1336 *piPreferrableMode = iFoundPreferrableMode;
1337
1338 return Status;
1339}
1340
1341#else
1342
1343/* Computes the size of a framebuffer. DualView has a few framebuffers of the computed size. */
1344void VBoxComputeFrameBufferSizes (PDEVICE_EXTENSION PrimaryExtension)
1345{
1346 ULONG ulAvailable = commonFromDeviceExt(PrimaryExtension)->cbVRAM
1347 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
1348 - VBVA_ADAPTER_INFORMATION_SIZE;
1349
1350 /* Size of a framebuffer. */
1351
1352 ULONG ulSize = ulAvailable / commonFromDeviceExt(PrimaryExtension)->cDisplays;
1353
1354 /* Align down to 4096 bytes. */
1355 ulSize &= ~0xFFF;
1356
1357 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X\n",
1358 commonFromDeviceExt(PrimaryExtension)->cbVRAM, commonFromDeviceExt(PrimaryExtension)->cDisplays,
1359 ulSize, ulSize * commonFromDeviceExt(PrimaryExtension)->cDisplays,
1360 ulAvailable - ulSize * commonFromDeviceExt(PrimaryExtension)->cDisplays));
1361
1362
1363 /* Update the primary info. */
1364 PrimaryExtension->u.primary.ulMaxFrameBufferSize = ulSize;
1365
1366 /* Update the per extension info. */
1367 PDEVICE_EXTENSION Extension = PrimaryExtension;
1368 ULONG ulFrameBufferOffset = 0;
1369 while (Extension)
1370 {
1371 Extension->ulFrameBufferOffset = ulFrameBufferOffset;
1372 /* That is assigned when a video mode is set. */
1373 Extension->ulFrameBufferSize = 0;
1374
1375 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: [%d] ulFrameBufferOffset 0x%08X\n",
1376 Extension->iDevice, ulFrameBufferOffset));
1377
1378 ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize;
1379
1380 Extension = Extension->pNext;
1381 }
1382}
1383
1384#endif
1385
1386int VBoxMapAdapterMemory (PVBOXVIDEO_COMMON pCommon, void **ppv, ULONG ulOffset, ULONG ulSize)
1387{
1388 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
1389 dprintf(("VBoxVideo::VBoxMapAdapterMemory 0x%08X[0x%X]\n", ulOffset, ulSize));
1390
1391 if (!ulSize)
1392 {
1393 dprintf(("Illegal length 0!\n"));
1394 return ERROR_INVALID_PARAMETER;
1395 }
1396
1397 PHYSICAL_ADDRESS FrameBuffer;
1398 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + ulOffset;
1399
1400 PVOID VideoRamBase = NULL;
1401 ULONG VideoRamLength = ulSize;
1402 VP_STATUS Status;
1403#ifndef VBOX_WITH_WDDM
1404 ULONG inIoSpace = 0;
1405
1406 Status = VideoPortMapMemory (PrimaryExtension, FrameBuffer,
1407 &VideoRamLength, &inIoSpace,
1408 &VideoRamBase);
1409#else
1410 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbMapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1411 FrameBuffer,
1412 VideoRamLength,
1413 FALSE, /* IN BOOLEAN InIoSpace */
1414 FALSE, /* IN BOOLEAN MapToUserMode */
1415 MmNonCached, /* IN MEMORY_CACHING_TYPE CacheType */
1416 &VideoRamBase /*OUT PVOID *VirtualAddress*/
1417 );
1418 Assert(ntStatus == STATUS_SUCCESS);
1419 Status = ntStatus == STATUS_SUCCESS ? NO_ERROR : ERROR_INVALID_PARAMETER; /*<- this is what VideoPortMapMemory returns according to the docs */
1420#endif
1421
1422 if (Status == NO_ERROR)
1423 {
1424 *ppv = VideoRamBase;
1425 }
1426
1427 dprintf(("VBoxVideo::VBoxMapAdapterMemory rc = %d\n", Status));
1428
1429 return Status;
1430}
1431
1432BOOLEAN VBoxUnmapAdpInfoCallback(PVOID ext)
1433{
1434 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)ext;
1435 Assert(PrimaryExtension);
1436
1437 commonFromDeviceExt(PrimaryExtension)->pHostFlags = NULL;
1438 return TRUE;
1439}
1440
1441void VBoxUnmapAdapterInformation(PDEVICE_EXTENSION PrimaryExtension)
1442{
1443 void *ppv;
1444
1445 dprintf(("VBoxVideo::VBoxUnmapAdapterInformation\n"));
1446
1447 ppv = commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation;
1448 if (ppv)
1449 {
1450#ifndef VBOX_WITH_WDDM
1451 /* The pHostFlags field is mapped through pvAdapterInformation. It must be cleared first,
1452 * and it must be done in a way which avoids races with the interrupt handler.
1453 */
1454 VideoPortSynchronizeExecution(PrimaryExtension, VpMediumPriority,
1455 VBoxUnmapAdpInfoCallback, PrimaryExtension);
1456 VideoPortUnmapMemory(PrimaryExtension, ppv, NULL);
1457#else
1458 BOOLEAN bRet;
1459 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1460 VBoxUnmapAdpInfoCallback, PrimaryExtension,
1461 0, &bRet);
1462 Assert(ntStatus == STATUS_SUCCESS);
1463 ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbUnmapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1464 ppv);
1465 Assert(ntStatus == STATUS_SUCCESS);
1466#endif
1467 commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation = NULL;
1468 }
1469}
1470
1471void VBoxUnmapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv, ULONG ulSize)
1472{
1473 dprintf(("VBoxVideo::VBoxUnmapAdapterMemory\n"));
1474
1475 if (*ppv)
1476 {
1477#ifndef VBOX_WITH_WDDM
1478 VideoPortUnmapMemory(PrimaryExtension, *ppv, NULL);
1479#else
1480 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbUnmapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1481 *ppv);
1482 Assert(ntStatus == STATUS_SUCCESS);
1483#endif
1484 }
1485
1486 *ppv = NULL;
1487}
1488
1489
1490void vboxVideoInitCustomVideoModes(PDEVICE_EXTENSION pDevExt)
1491{
1492 VP_STATUS status;
1493 VBOXCMNREG Reg;
1494
1495 VBoxVideoCmnRegInit(pDevExt, &Reg);
1496
1497 dprintf(("VBoxVideo::vboxVideoInitCustomVideoModes\n"));
1498
1499#ifndef VBOX_WITH_MULTIMONITOR_FIX
1500 /*
1501 * Get the last custom resolution
1502 */
1503 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomXRes", &gCustomXRes);
1504 if (status != NO_ERROR)
1505 gCustomXRes = 0;
1506
1507 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomYRes", &gCustomYRes);
1508 if (status != NO_ERROR)
1509 gCustomYRes = 0;
1510 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomBPP", &gCustomBPP);
1511 if (status != NO_ERROR)
1512 gCustomBPP = 0;
1513
1514 dprintf(("VBoxVideo: got stored custom resolution %dx%dx%d\n", gCustomXRes, gCustomYRes, gCustomBPP));
1515#else
1516 /* Initialize all custom modes to the 800x600x32. */
1517 initVideoModeInformation(&CustomVideoModes[0], 800, 600, 32, 0, 0);
1518
1519 int iCustomMode;
1520 for (iCustomMode = 1; iCustomMode < RT_ELEMENTS(CustomVideoModes); iCustomMode++)
1521 {
1522 CustomVideoModes[iCustomMode] = CustomVideoModes[0];
1523 }
1524
1525 /* Load stored custom resolution from the registry. */
1526 for (iCustomMode = 0;
1527#ifdef VBOX_WITH_WDDM
1528 iCustomMode < commonFromDeviceExt(pDevExt)->cDisplays;
1529#else
1530 iCustomMode < commonFromDeviceExt(pDevExt)->cDisplays;
1531#endif
1532 iCustomMode++)
1533 {
1534 /*
1535 * Get the last custom resolution
1536 */
1537 uint32_t CustomXRes = 0, CustomYRes = 0, CustomBPP = 0;
1538
1539 if (iCustomMode == 0)
1540 {
1541 /* Name without a suffix */
1542 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomXRes", &CustomXRes);
1543 if (status != NO_ERROR)
1544 CustomXRes = 0;
1545 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomYRes", &CustomYRes);
1546 if (status != NO_ERROR)
1547 CustomYRes = 0;
1548 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomBPP", &CustomBPP);
1549 if (status != NO_ERROR)
1550 CustomBPP = 0;
1551 }
1552 else
1553 {
1554 wchar_t keyname[32];
1555 swprintf(keyname, L"CustomXRes%d", iCustomMode);
1556 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomXRes);
1557 if (status != NO_ERROR)
1558 CustomXRes = 0;
1559 swprintf(keyname, L"CustomYRes%d", iCustomMode);
1560 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomYRes);
1561 if (status != NO_ERROR)
1562 CustomYRes = 0;
1563 swprintf(keyname, L"CustomBPP%d", iCustomMode);
1564 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomBPP);
1565 if (status != NO_ERROR)
1566 CustomBPP = 0;
1567 }
1568
1569 dprintf(("VBoxVideo: got stored custom resolution[%d] %dx%dx%d\n", iCustomMode, CustomXRes, CustomYRes, CustomBPP));
1570
1571 if (CustomXRes || CustomYRes || CustomBPP)
1572 {
1573 if (CustomXRes == 0)
1574 {
1575 CustomXRes = CustomVideoModes[iCustomMode].VisScreenWidth;
1576 }
1577 if (CustomYRes == 0)
1578 {
1579 CustomYRes = CustomVideoModes[iCustomMode].VisScreenHeight;
1580 }
1581 if (CustomBPP == 0)
1582 {
1583 CustomBPP = CustomVideoModes[iCustomMode].BitsPerPlane;
1584 }
1585
1586 initVideoModeInformation(&CustomVideoModes[iCustomMode], CustomXRes, CustomYRes, CustomBPP, 0, 0);
1587 }
1588 }
1589#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1590
1591 VBoxVideoCmnRegFini(Reg);
1592}
1593
1594#ifndef VBOX_WITH_WDDM
1595
1596VP_STATUS VBoxVideoFindAdapter(IN PVOID HwDeviceExtension,
1597 IN PVOID HwContext, IN PWSTR ArgumentString,
1598 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
1599 OUT PUCHAR Again)
1600{
1601 VP_STATUS rc;
1602 USHORT DispiId;
1603 ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
1604
1605 dprintf(("VBoxVideo::VBoxVideoFindAdapter %p\n", HwDeviceExtension));
1606
1607 VBoxSetupVideoPortFunctions((PDEVICE_EXTENSION)HwDeviceExtension, &((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.VideoPortProcs, ConfigInfo);
1608
1609 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1610 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
1611 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
1612 if (DispiId == VBE_DISPI_ID2)
1613 {
1614 dprintf(("VBoxVideo::VBoxVideoFoundAdapter: found the VBE card\n"));
1615 /*
1616 * Write some hardware information to registry, so that
1617 * it's visible in Windows property dialog.
1618 */
1619
1620 rc = VideoPortSetRegistryParameters(
1621 HwDeviceExtension,
1622 L"HardwareInformation.ChipType",
1623 VBoxChipType,
1624 sizeof(VBoxChipType));
1625
1626 rc = VideoPortSetRegistryParameters(
1627 HwDeviceExtension,
1628 L"HardwareInformation.DacType",
1629 VBoxDACType,
1630 sizeof(VBoxDACType));
1631
1632 /*
1633 * Query the adapter's memory size. It's a bit of a hack, we just read
1634 * an ULONG from the data port without setting an index before.
1635 */
1636 AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
1637 rc = VideoPortSetRegistryParameters(
1638 HwDeviceExtension,
1639 L"HardwareInformation.MemorySize",
1640 &AdapterMemorySize,
1641 sizeof(ULONG));
1642
1643 rc = VideoPortSetRegistryParameters(
1644 HwDeviceExtension,
1645 L"HardwareInformation.AdapterString",
1646 VBoxAdapterString,
1647 sizeof(VBoxAdapterString));
1648
1649 rc = VideoPortSetRegistryParameters(
1650 HwDeviceExtension,
1651 L"HardwareInformation.BiosString",
1652 VBoxBiosString,
1653 sizeof(VBoxBiosString));
1654
1655 dprintf(("VBoxVideo::VBoxVideoFindAdapter: calling VideoPortGetAccessRanges\n"));
1656
1657 VIDEO_ACCESS_RANGE tmpRanges[4];
1658 ULONG slot = 0;
1659
1660 VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));
1661
1662 /* need to call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up */
1663 VP_STATUS status;
1664 if (vboxQueryWinVersion() == WINNT4)
1665 {
1666 /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
1667 * and needs PCI ids for a successful VideoPortGetAccessRanges call.
1668 */
1669 ULONG vendorId = 0x80EE;
1670 ULONG deviceId = 0xBEEF;
1671 status = VideoPortGetAccessRanges(HwDeviceExtension,
1672 0,
1673 NULL,
1674 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1675 tmpRanges,
1676 &vendorId,
1677 &deviceId,
1678 &slot);
1679 }
1680 else
1681 {
1682 status = VideoPortGetAccessRanges(HwDeviceExtension,
1683 0,
1684 NULL,
1685 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1686 tmpRanges,
1687 NULL,
1688 NULL,
1689 &slot);
1690 }
1691 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortGetAccessRanges status 0x%x\n", status));
1692
1693 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
1694 rc = VbglInit ();
1695 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
1696
1697 /* Preinitialize the primary extension.
1698 */
1699 ((PDEVICE_EXTENSION)HwDeviceExtension)->pNext = NULL;
1700 ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary = (PDEVICE_EXTENSION)HwDeviceExtension;
1701 ((PDEVICE_EXTENSION)HwDeviceExtension)->iDevice = 0;
1702 ((PDEVICE_EXTENSION)HwDeviceExtension)->ulFrameBufferOffset = 0;
1703 ((PDEVICE_EXTENSION)HwDeviceExtension)->ulFrameBufferSize = 0;
1704 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.ulVbvaEnabled = 0;
1705 VBoxVideoCmnMemZero(&((PDEVICE_EXTENSION)HwDeviceExtension)->areaDisplay, sizeof(HGSMIAREA));
1706 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
1707 * code will be ifdef'ed and later removed.
1708 * The host will however support both old and new interface to keep compatibility
1709 * with old guest additions.
1710 */
1711 VBoxSetupDisplaysHGSMI((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize, 0);
1712
1713 if (commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension)->bHGSMI)
1714 {
1715 LogRel(("VBoxVideo: using HGSMI\n"));
1716 }
1717
1718 // pretend success to make the driver work.
1719 rc = NO_ERROR;
1720 } else
1721 {
1722 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
1723 rc = ERROR_DEV_NOT_EXIST;
1724 }
1725 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
1726 return rc;
1727}
1728
1729/**
1730 * VBoxVideoInitialize
1731 *
1732 * Performs the first initialization of the adapter, after the HAL has given
1733 * up control of the video hardware to the video port driver.
1734 */
1735BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
1736{
1737 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
1738
1739 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1740 USHORT DispiId;
1741
1742 /* Initialize the request pointer. */
1743 pDevExt->u.primary.pvReqFlush = NULL;
1744
1745 /* Check if the chip restricts horizontal resolution or not. */
1746 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1747 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
1748 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
1749 if (DispiId == VBE_DISPI_ID_ANYX)
1750 pDevExt->fAnyX = TRUE;
1751 else
1752 pDevExt->fAnyX = FALSE;
1753
1754 vboxVideoInitCustomVideoModes(pDevExt);
1755
1756 return TRUE;
1757}
1758
1759# ifdef VBOX_WITH_VIDEOHWACCEL
1760
1761BOOLEAN VBoxVideoInterrupt(PVOID HwDeviceExtension)
1762{
1763 PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1764 PDEVICE_EXTENSION PrimaryExtension = devExt->pPrimary;
1765 if (PrimaryExtension)
1766 {
1767 if (commonFromDeviceExt(PrimaryExtension)->pHostFlags) /* If HGSMI is enabled at all. */
1768 {
1769 uint32_t flags = commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags;
1770 if((flags & HGSMIHOSTFLAGS_IRQ) != 0)
1771 {
1772 if((flags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0)
1773 {
1774 /* schedule a DPC*/
1775 BOOLEAN bResult = PrimaryExtension->u.primary.VideoPortProcs.pfnQueueDpc(PrimaryExtension, VBoxVideoHGSMIDpc, (PVOID)1);
1776 Assert(bResult);
1777 }
1778 /* clear the IRQ */
1779 HGSMIClearIrq (commonFromDeviceExt(PrimaryExtension));
1780 return TRUE;
1781 }
1782 }
1783 }
1784 return FALSE;
1785}
1786# endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
1787#endif /* #ifndef VBOX_WITH_WDDM */
1788/**
1789 * Send a request to the host to make the absolute pointer visible
1790 */
1791static BOOLEAN ShowPointer(PVOID HwDeviceExtension)
1792{
1793 BOOLEAN Result = TRUE;
1794
1795 /* Use primary device extension, because the show pointer request should be processed
1796 * in vboxUpdatePointerShape regardless of the device. */
1797#ifndef VBOX_WITH_WDDM
1798 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary;
1799#else
1800 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
1801#endif
1802
1803 if (DEV_MOUSE_HIDDEN(PrimaryExtension))
1804 {
1805 // tell the host to use the guest's pointer
1806 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1807
1808 /* Visible and No Shape means Show the pointer.
1809 * It is enough to init only this field.
1810 */
1811 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
1812
1813 Result = vboxUpdatePointerShape(PrimaryExtension, &PointerAttributes, sizeof (PointerAttributes));
1814
1815 if (Result)
1816 DEV_SET_MOUSE_SHOWN(PrimaryExtension);
1817 else
1818 dprintf(("VBoxVideo::ShowPointer: Could not show the hardware pointer -> fallback\n"));
1819 }
1820 return Result;
1821}
1822
1823#ifndef VBOX_WITH_WDDM
1824/**
1825 * VBoxVideoStartIO
1826 *
1827 * Processes the specified Video Request Packet.
1828 */
1829BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
1830 PVIDEO_REQUEST_PACKET RequestPacket)
1831{
1832 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1833
1834 BOOLEAN Result;
1835
1836// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
1837
1838 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1839
1840 switch (RequestPacket->IoControlCode)
1841 {
1842 case IOCTL_VIDEO_SET_CURRENT_MODE:
1843 {
1844 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
1845 {
1846 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1847 return TRUE;
1848 }
1849 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1850 (PVIDEO_MODE)RequestPacket->InputBuffer,
1851 RequestPacket->StatusBlock);
1852 break;
1853 }
1854
1855 case IOCTL_VIDEO_RESET_DEVICE:
1856 {
1857 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
1858 RequestPacket->StatusBlock);
1859 break;
1860 }
1861
1862 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
1863 {
1864 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
1865 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1866 {
1867 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1868 return TRUE;
1869 }
1870 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1871 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1872 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
1873 RequestPacket->StatusBlock);
1874 break;
1875 }
1876
1877 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
1878 {
1879 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1880 {
1881 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1882 return TRUE;
1883 }
1884 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1885 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1886 RequestPacket->StatusBlock);
1887 break;
1888 }
1889
1890 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
1891 {
1892 PVIDEO_SHARE_MEMORY pShareMemory;
1893 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
1894 PHYSICAL_ADDRESS shareAddress;
1895 PVOID virtualAddress = NULL;
1896 ULONG sharedViewSize;
1897 ULONG inIoSpace = 0;
1898 VP_STATUS status;
1899
1900 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
1901
1902 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
1903 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
1904
1905 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1906 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1907 Result = FALSE;
1908 break;
1909 }
1910
1911 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1912
1913 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
1914 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
1915
1916 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INVALID_PARAMETER %x:%x size %x\n", pShareMemory->ViewOffset, pShareMemory->ViewSize, pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize));
1917 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
1918 Result = FALSE;
1919 break;
1920 }
1921
1922 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
1923
1924 virtualAddress = pShareMemory->ProcessHandle;
1925 sharedViewSize = pShareMemory->ViewSize;
1926
1927 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
1928
1929 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
1930 if (status != NO_ERROR)
1931 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
1932 Result = (status == NO_ERROR);
1933
1934 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
1935 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
1936 pShareMemoryInformation->VirtualAddress = virtualAddress;
1937 pShareMemoryInformation->SharedViewSize = sharedViewSize;
1938 break;
1939 }
1940
1941 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
1942 {
1943 PVIDEO_SHARE_MEMORY pShareMemory;
1944 VP_STATUS status;
1945
1946 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
1947
1948 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
1949 {
1950 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1951 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1952 Result = FALSE;
1953 break;
1954 }
1955
1956 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1957
1958 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
1959 if (status != NO_ERROR)
1960 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
1961 Result = (status == NO_ERROR);
1962 break;
1963 }
1964
1965 /*
1966 * The display driver asks us how many video modes we support
1967 * so that it can supply an appropriate buffer for the next call.
1968 */
1969 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
1970 {
1971 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
1972 {
1973 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1974 return TRUE;
1975 }
1976 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1977 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
1978 RequestPacket->StatusBlock);
1979 break;
1980 }
1981
1982 /*
1983 * The display driver asks us to provide a list of supported video modes
1984 * into a buffer it has allocated.
1985 */
1986 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
1987 {
1988 if (RequestPacket->OutputBufferLength <
1989 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
1990 {
1991 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1992 return TRUE;
1993 }
1994 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1995 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1996 RequestPacket->StatusBlock);
1997 break;
1998 }
1999
2000 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
2001 {
2002 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
2003 RequestPacket->InputBufferLength <
2004 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
2005 sizeof(VIDEO_CLUT))
2006 {
2007 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2008 return TRUE;
2009 }
2010 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
2011 (PVIDEO_CLUT)RequestPacket->InputBuffer,
2012 RequestPacket->StatusBlock);
2013 break;
2014 }
2015
2016 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
2017 {
2018 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
2019 {
2020 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2021 return TRUE;
2022 }
2023 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
2024 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
2025 RequestPacket->StatusBlock);
2026 break;
2027 }
2028
2029 // show the pointer
2030 case IOCTL_VIDEO_ENABLE_POINTER:
2031 {
2032 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
2033 // find out whether the host wants absolute positioning
2034 /// @todo this is now obsolete - remove it?
2035 if (vboxQueryHostWantsAbsolute())
2036 Result = ShowPointer(HwDeviceExtension);
2037 else
2038 {
2039 // fallback to software pointer
2040 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2041 Result = FALSE;
2042 }
2043 break;
2044 }
2045
2046 // hide the pointer
2047 case IOCTL_VIDEO_DISABLE_POINTER:
2048 {
2049 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
2050 // find out whether the host wants absolute positioning
2051 if (vboxQueryHostWantsAbsolute())
2052 {
2053 // tell the host to hide pointer
2054 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
2055
2056 /* Enable == 0 means no shape, not visible.
2057 * It is enough to init only this field.
2058 */
2059 PointerAttributes.Enable = 0;
2060
2061 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, &PointerAttributes, sizeof (PointerAttributes));
2062
2063 if (Result)
2064 DEV_SET_MOUSE_HIDDEN((PDEVICE_EXTENSION)HwDeviceExtension);
2065 else
2066 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
2067 } else
2068 {
2069 // fallback to software pointer
2070 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2071 Result = FALSE;
2072 }
2073 break;
2074 }
2075
2076 /*
2077 * Change the pointer shape
2078 */
2079 case IOCTL_VIDEO_SET_POINTER_ATTR:
2080 {
2081 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
2082 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
2083 {
2084 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
2085 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2086 return TRUE;
2087 }
2088 // find out whether the host wants absolute positioning
2089 if (vboxQueryHostWantsAbsolute())
2090 {
2091 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
2092#if 0
2093 dprintf(("Pointer shape information:\n"
2094 "\tFlags: %d\n"
2095 "\tWidth: %d\n"
2096 "\tHeight: %d\n"
2097 "\tWidthInBytes: %d\n"
2098 "\tEnable: %d\n"
2099 "\tColumn: %d\n"
2100 "\tRow: %d\n",
2101 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
2102 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
2103 pPointerAttributes->Row));
2104 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
2105#endif
2106 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, pPointerAttributes, RequestPacket->InputBufferLength);
2107 if (!Result)
2108 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
2109 } else
2110 {
2111 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
2112 // fallback to software pointer
2113 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2114 Result = FALSE;
2115 }
2116 break;
2117 }
2118
2119 // query pointer information
2120 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
2121 {
2122 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
2123 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2124 Result = FALSE;
2125 break;
2126 }
2127
2128 // set the pointer position
2129 case IOCTL_VIDEO_SET_POINTER_POSITION:
2130 {
2131 // find out whether the host wants absolute positioning
2132 /// @todo this is now obsolete - remove it?
2133 if (vboxQueryHostWantsAbsolute())
2134 Result = ShowPointer(HwDeviceExtension);
2135 else
2136 {
2137 // fallback to software pointer
2138 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2139 Result = FALSE;
2140 }
2141 break;
2142 }
2143
2144 // query the pointer position
2145 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
2146 {
2147 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
2148 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
2149 {
2150 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2151 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2152 return TRUE;
2153 }
2154 Result = FALSE;
2155 uint16_t mousePosX;
2156 uint16_t mousePosY;
2157 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
2158 {
2159 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
2160 PVIDEO_MODE_INFORMATION ModeInfo;
2161 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
2162 // map from 0xFFFF to the current resolution
2163 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
2164 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
2165 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
2166 Result = TRUE;
2167 }
2168 if (!Result)
2169 {
2170 // fallback to software pointer
2171 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2172 }
2173 break;
2174 }
2175
2176 // Determine hardware cursor capabilities. We will always report that we are
2177 // very capable even though the host might not want to do pointer integration.
2178 // This is done because we can still return errors on the actual calls later to
2179 // make the display driver go to the fallback routines.
2180 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
2181 {
2182 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
2183 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
2184 {
2185 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2186 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2187 return TRUE;
2188 }
2189 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
2190 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
2191 VIDEO_MODE_COLOR_POINTER |
2192 VIDEO_MODE_MONO_POINTER;
2193 // for now we go with 64x64 cursors
2194 pCaps->MaxWidth = 64;
2195 pCaps->MaxHeight = 64;
2196 // that doesn't seem to be relevant, VBoxDisp doesn't use it
2197 pCaps->HWPtrBitmapStart = -1;
2198 pCaps->HWPtrBitmapEnd = -1;
2199 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
2200 Result = TRUE;
2201 break;
2202 }
2203
2204 /* Attach/detach DualView devices */
2205 case IOCTL_VIDEO_SWITCH_DUALVIEW:
2206 {
2207 ULONG ulAttach;
2208
2209 ulAttach = *((PULONG)RequestPacket->InputBuffer);
2210 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
2211
2212 if (pDevExt->iDevice > 0)
2213 {
2214 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
2215 }
2216 Result = TRUE;
2217 break;
2218 }
2219
2220 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
2221 {
2222 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
2223 /* Pre-HGSMI IOCTL */
2224 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2225 Result = false;
2226 break;
2227 }
2228
2229
2230 case IOCTL_VIDEO_VBVA_ENABLE:
2231 {
2232 int rc;
2233 ULONG ulEnable;
2234
2235 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
2236
2237 if (RequestPacket->InputBufferLength < sizeof(ULONG))
2238 {
2239 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
2240 RequestPacket->InputBufferLength, sizeof(ULONG)));
2241 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2242 return FALSE;
2243 }
2244
2245 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
2246 {
2247 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2248 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
2249 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2250 return FALSE;
2251 }
2252
2253 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
2254 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
2255
2256 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
2257 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Rrc\n", rc));
2258
2259 if (RT_FAILURE (rc))
2260 {
2261 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
2262 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2263 return FALSE;
2264 }
2265
2266 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
2267 Result = TRUE;
2268
2269 break;
2270 }
2271
2272 /* Private ioctls */
2273 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
2274 {
2275 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
2276 int rc;
2277
2278 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
2279 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
2280 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
2281 {
2282 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
2283 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
2284 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2285 return FALSE;
2286 }
2287 /*
2288 * Inform the host about the visible region
2289 */
2290 VMMDevVideoSetVisibleRegion *req = NULL;
2291
2292 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2293 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
2294 VMMDevReq_VideoSetVisibleRegion);
2295
2296 if (RT_SUCCESS(rc))
2297 {
2298 req->cRect = cRect;
2299 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
2300
2301 rc = VbglGRPerform (&req->header);
2302
2303 if (RT_SUCCESS(rc))
2304 {
2305 Result = TRUE;
2306 break;
2307 }
2308 }
2309
2310 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x\n", rc));
2311 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2312 return FALSE;
2313 }
2314
2315 case IOCTL_VIDEO_QUERY_HGSMI_INFO:
2316 {
2317 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_HGSMI_INFO\n"));
2318
2319 if (RequestPacket->OutputBufferLength < sizeof(QUERYHGSMIRESULT))
2320 {
2321 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2322 RequestPacket->OutputBufferLength, sizeof(QUERYHGSMIRESULT)));
2323 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2324 return FALSE;
2325 }
2326
2327 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2328 {
2329 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2330 return FALSE;
2331 }
2332
2333 QUERYHGSMIRESULT *pInfo = (QUERYHGSMIRESULT *)RequestPacket->OutputBuffer;
2334
2335 pInfo->iDevice = pDevExt->iDevice;
2336 pInfo->ulFlags = 0;
2337
2338 /* Describes VRAM chunk for this display device. */
2339 pInfo->areaDisplay = pDevExt->areaDisplay;
2340
2341 pInfo->u32DisplayInfoSize = VBVA_DISPLAY_INFORMATION_SIZE;
2342 pInfo->u32MinVBVABufferSize = VBVA_MIN_BUFFER_SIZE;
2343
2344 pInfo->IOPortGuestCommand = commonFromDeviceExt(pDevExt)->IOPortGuest;
2345
2346 RequestPacket->StatusBlock->Information = sizeof(QUERYHGSMIRESULT);
2347 Result = TRUE;
2348
2349 break;
2350 }
2351 case IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS:
2352 {
2353 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS\n"));
2354
2355 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCALLBACKS))
2356 {
2357 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2358 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCALLBACKS)));
2359 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2360 return FALSE;
2361 }
2362
2363 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2364 {
2365 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2366 return FALSE;
2367 }
2368
2369 HGSMIQUERYCALLBACKS *pInfo = (HGSMIQUERYCALLBACKS *)RequestPacket->OutputBuffer;
2370
2371 pInfo->hContext = pDevExt;
2372 pInfo->pfnCompletionHandler = hgsmiHostCmdComplete;
2373 pInfo->pfnRequestCommandsHandler = hgsmiHostCmdRequest;
2374
2375 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCALLBACKS);
2376 Result = TRUE;
2377 break;
2378 }
2379 case IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS:
2380 {
2381 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS\n"));
2382
2383 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCPORTPROCS))
2384 {
2385 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2386 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCPORTPROCS)));
2387 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2388 return FALSE;
2389 }
2390
2391 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2392 {
2393 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2394 return FALSE;
2395 }
2396
2397 HGSMIQUERYCPORTPROCS *pInfo = (HGSMIQUERYCPORTPROCS *)RequestPacket->OutputBuffer;
2398 pInfo->pContext = pDevExt->pPrimary;
2399 pInfo->VideoPortProcs = pDevExt->pPrimary->u.primary.VideoPortProcs;
2400
2401 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCPORTPROCS);
2402 Result = TRUE;
2403 break;
2404 }
2405 case IOCTL_VIDEO_HGSMI_HANDLER_ENABLE:
2406 {
2407 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_HANDLER_ENABLE\n"));
2408
2409 if (RequestPacket->InputBufferLength< sizeof(HGSMIHANDLERENABLE))
2410 {
2411 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2412 RequestPacket->InputBufferLength, sizeof(HGSMIHANDLERENABLE)));
2413 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2414 return FALSE;
2415 }
2416
2417 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2418 {
2419 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2420 return FALSE;
2421 }
2422
2423 HGSMIHANDLERENABLE *pInfo = (HGSMIHANDLERENABLE *)RequestPacket->InputBuffer;
2424
2425 int rc = vboxVBVAChannelDisplayEnable(pDevExt->pPrimary,
2426 pDevExt->iDevice,
2427 pInfo->u8Channel);
2428 if(RT_FAILURE(rc))
2429 {
2430 RequestPacket->StatusBlock->Status = ERROR_INVALID_NAME;
2431 }
2432 Result = TRUE;
2433 break;
2434 }
2435 case IOCTL_VIDEO_HGSMI_HANDLER_DISABLE:
2436 {
2437 /* TODO: implement */
2438 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2439 {
2440 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2441 return FALSE;
2442 }
2443 break;
2444 }
2445# ifdef VBOX_WITH_VIDEOHWACCEL
2446 case IOCTL_VIDEO_VHWA_QUERY_INFO:
2447 {
2448 if (RequestPacket->OutputBufferLength < sizeof (VHWAQUERYINFO))
2449 {
2450 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2451 RequestPacket->OutputBufferLength, sizeof(VHWAQUERYINFO)));
2452 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2453 return FALSE;
2454 }
2455
2456 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2457 {
2458 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2459 return FALSE;
2460 }
2461
2462 VHWAQUERYINFO *pInfo = (VHWAQUERYINFO *)RequestPacket->OutputBuffer;
2463 pInfo->offVramBase = (ULONG_PTR)pDevExt->ulFrameBufferOffset;
2464 RequestPacket->StatusBlock->Information = sizeof (VHWAQUERYINFO);
2465 Result = TRUE;
2466 break;
2467 }
2468# endif
2469 default:
2470 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
2471 RequestPacket->IoControlCode,
2472 (RequestPacket->IoControlCode >> 2) & 0xFFF,
2473 (RequestPacket->IoControlCode >> 2) & 0xFFF));
2474 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2475 return FALSE;
2476 }
2477
2478 if (Result)
2479 RequestPacket->StatusBlock->Status = NO_ERROR;
2480 else
2481 RequestPacket->StatusBlock->Information = 0;
2482
2483// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
2484
2485 return TRUE;
2486}
2487
2488/**
2489 * VBoxVideoReset HW
2490 *
2491 * Resets the video hardware.
2492 */
2493BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
2494{
2495 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
2496
2497 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2498
2499 if (pDevExt->iDevice > 0)
2500 {
2501 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
2502 pDevExt->iDevice));
2503 return TRUE;
2504 }
2505
2506 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2507 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2508
2509 if (pDevExt->u.primary.pvReqFlush != NULL)
2510 {
2511 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
2512 pDevExt->u.primary.pvReqFlush = NULL;
2513 }
2514
2515 VbglTerminate ();
2516
2517 VBoxUnmapAdapterMemory (pDevExt, &commonFromDeviceExt(pDevExt)->pvMiniportHeap, commonFromDeviceExt(pDevExt)->cbMiniportHeap);
2518 VBoxUnmapAdapterInformation (pDevExt);
2519
2520 return TRUE;
2521}
2522
2523/**
2524 * VBoxVideoGetPowerState
2525 *
2526 * Queries whether the device can support the requested power state.
2527 */
2528VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2529 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2530{
2531 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
2532 return NO_ERROR;
2533}
2534
2535/**
2536 * VBoxVideoSetPowerState
2537 *
2538 * Sets the power state of the specified device
2539 */
2540VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2541 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2542{
2543 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
2544 return NO_ERROR;
2545}
2546#endif /* #ifndef VBOX_WITH_WDDM */
2547
2548/**
2549 * VBoxVideoSetGraphicsCap
2550 *
2551 * Tells the host whether or not we currently support graphics in the
2552 * additions
2553 */
2554BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
2555{
2556 VMMDevReqGuestCapabilities2 *req = NULL;
2557 int rc;
2558
2559 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2560 sizeof (VMMDevReqGuestCapabilities2),
2561 VMMDevReq_SetGuestCapabilities);
2562
2563 if (!RT_SUCCESS(rc))
2564 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
2565 else
2566 {
2567 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
2568 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2569
2570 rc = VbglGRPerform (&req->header);
2571 if (RT_FAILURE(rc))
2572 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc\n", rc));
2573 }
2574 if (req != NULL)
2575 VbglGRFree (&req->header);
2576 return RT_SUCCESS(rc);
2577}
2578
2579
2580BOOLEAN FASTCALL VBoxVideoSetCurrentModePerform(PDEVICE_EXTENSION DeviceExtension,
2581 USHORT width, USHORT height, USHORT bpp
2582#ifdef VBOX_WITH_WDDM
2583 , ULONG offDisplay
2584#endif
2585 )
2586{
2587 /* set the mode characteristics */
2588 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
2589 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, width);
2590 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
2591 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, height);
2592 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
2593 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, bpp);
2594 /* enable the mode */
2595 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2596 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
2597#ifdef VBOX_WITH_WDDM
2598 /* encode linear offDisplay to xOffset & yOffset to ensure offset fits USHORT */
2599 ULONG cbLine = VBOXWDDM_ROUNDBOUND(((width * bpp) + 7) / 8, 4);
2600 ULONG xOffset = offDisplay % cbLine;
2601 if (bpp == 4)
2602 {
2603 xOffset <<= 1;
2604 }
2605 else
2606 {
2607 Assert(!(xOffset%((bpp + 7) >> 3)));
2608 xOffset /= ((bpp + 7) >> 3);
2609 }
2610 ULONG yOffset = offDisplay / cbLine;
2611 Assert(xOffset <= 0xffff);
2612 Assert(yOffset <= 0xffff);
2613 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET);
2614 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)xOffset);
2615 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET);
2616 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)yOffset);
2617#endif
2618 /** @todo read from the port to see if the mode switch was successful */
2619
2620 /* Tell the host that we now support graphics in the additions.
2621 * @todo: Keep old behaviour, because VBoxVideoResetDevice is called on every graphics
2622 * mode switch and causes an OFF/ON sequence which is not handled by frontends
2623 * (for example Qt GUI debug build asserts when seamless is being enabled).
2624 */
2625 // VBoxVideoSetGraphicsCap(TRUE);
2626
2627 return TRUE;
2628}
2629
2630#ifndef VBOX_WITH_WDDM
2631
2632/**
2633 * VBoxVideoSetCurrentMode
2634 *
2635 * Sets the adapter to the specified operating mode.
2636 */
2637BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2638 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
2639{
2640 PVIDEO_MODE_INFORMATION ModeInfo;
2641
2642 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
2643
2644 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
2645 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
2646 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
2647 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
2648
2649 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
2650 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
2651 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
2652
2653 if (DeviceExtension->iDevice > 0)
2654 {
2655 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
2656 DeviceExtension->iDevice));
2657 return TRUE;
2658 }
2659
2660 return VBoxVideoSetCurrentModePerform(DeviceExtension,
2661 (USHORT)ModeInfo->VisScreenWidth,
2662 (USHORT)ModeInfo->VisScreenHeight,
2663 (USHORT)ModeInfo->BitsPerPlane);
2664}
2665
2666/*
2667 * VBoxVideoResetDevice
2668 *
2669 * Resets the video hardware to the default mode, to which it was initialized
2670 * at system boot.
2671 */
2672
2673BOOLEAN FASTCALL VBoxVideoResetDevice(
2674 PDEVICE_EXTENSION DeviceExtension,
2675 PSTATUS_BLOCK StatusBlock)
2676{
2677 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
2678
2679 if (DeviceExtension->iDevice > 0)
2680 {
2681 /* If the device is the secondary display, however, it is recommended that no action be taken. */
2682 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
2683 DeviceExtension->iDevice));
2684 return TRUE;
2685 }
2686
2687#if 0
2688 /* Don't disable the extended video mode. This would only switch the video mode
2689 * to <current width> x <current height> x 0 bpp which is not what we want. And
2690 * even worse, it causes an disturbing additional mode switch */
2691 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2692 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2693#endif
2694
2695 /* Tell the host that we no longer support graphics in the additions
2696 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
2697 */
2698 // VBoxVideoSetGraphicsCap(FALSE);
2699 return TRUE;
2700}
2701
2702/**
2703 * VBoxVideoMapVideoMemory
2704 *
2705 * Maps the video hardware frame buffer and video RAM into the virtual address
2706 * space of the requestor.
2707 */
2708BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2709 PVIDEO_MEMORY RequestedAddress,
2710 PVIDEO_MEMORY_INFORMATION MapInformation,
2711 PSTATUS_BLOCK StatusBlock)
2712{
2713 PHYSICAL_ADDRESS FrameBuffer;
2714 ULONG inIoSpace = 0;
2715 VP_STATUS Status;
2716
2717 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory: fb offset 0x%x\n", DeviceExtension->ulFrameBufferOffset));
2718
2719 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
2720
2721 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
2722 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
2723
2724 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
2725 &MapInformation->VideoRamLength, &inIoSpace,
2726 &MapInformation->VideoRamBase);
2727
2728 if (Status == NO_ERROR)
2729 {
2730 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
2731 MapInformation->FrameBufferLength =
2732 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
2733 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
2734 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
2735
2736 /* Save the new framebuffer size */
2737 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
2738 HGSMIAreaInitialize (&DeviceExtension->areaDisplay,
2739 MapInformation->FrameBufferBase,
2740 MapInformation->FrameBufferLength,
2741 DeviceExtension->ulFrameBufferOffset);
2742 return TRUE;
2743 }
2744
2745 return FALSE;
2746}
2747
2748/**
2749 * VBoxVideoUnmapVideoMemory
2750 *
2751 * Releases a mapping between the virtual address space and the adapter's
2752 * frame buffer and video RAM.
2753 */
2754BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2755 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
2756{
2757 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
2758 HGSMIAreaClear (&DeviceExtension->areaDisplay);
2759 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
2760 return TRUE;
2761}
2762
2763/**
2764 * VBoxVideoQueryNumAvailModes
2765 *
2766 * Returns the number of video modes supported by the adapter and the size
2767 * in bytes of the video mode information, which can be used to allocate a
2768 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
2769 */
2770BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
2771 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
2772{
2773 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
2774 /* calculate the video modes table */
2775 VBoxBuildModesTable(DeviceExtension);
2776 Modes->NumModes = gNumVideoModes;
2777 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
2778 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
2779 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
2780 return TRUE;
2781}
2782
2783/**
2784 * VBoxVideoQueryAvailModes
2785 *
2786 * Returns information about each video mode supported by the adapter.
2787 */
2788BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
2789 PVIDEO_MODE_INFORMATION ReturnedModes,
2790 PSTATUS_BLOCK StatusBlock)
2791{
2792 ULONG Size;
2793
2794 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
2795
2796 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
2797 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
2798 StatusBlock->Information = Size;
2799
2800 return TRUE;
2801}
2802
2803/**
2804 * VBoxVideoQueryCurrentMode
2805 *
2806 * Returns information about current video mode.
2807 */
2808BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2809 PVIDEO_MODE_INFORMATION VideoModeInfo,
2810 PSTATUS_BLOCK StatusBlock)
2811{
2812 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
2813
2814 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
2815 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
2816
2817 return TRUE;
2818}
2819#endif /* ifndef VBOX_WITH_WDDM */
2820/*
2821 * VBoxVideoSetColorRegisters
2822 *
2823 * Sets the adapter's color registers to the specified RGB values. There
2824 * are code paths in this function, one generic and one for VGA compatible
2825 * controllers. The latter is needed for Bochs, where the generic one isn't
2826 * yet implemented.
2827 */
2828
2829BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
2830 PDEVICE_EXTENSION DeviceExtension,
2831 PVIDEO_CLUT ColorLookUpTable,
2832 PSTATUS_BLOCK StatusBlock)
2833{
2834 LONG Entry;
2835
2836 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
2837
2838 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
2839 return FALSE;
2840
2841 for (Entry = ColorLookUpTable->FirstEntry;
2842 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
2843 Entry++)
2844 {
2845 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c8, (UCHAR)Entry);
2846 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
2847 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
2848 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
2849 }
2850
2851 return TRUE;
2852}
2853
2854#ifndef VBOX_WITH_WDDM
2855
2856VP_STATUS VBoxVideoGetChildDescriptor(
2857 PVOID HwDeviceExtension,
2858 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
2859 PVIDEO_CHILD_TYPE VideoChildType,
2860 PUCHAR pChildDescriptor,
2861 PULONG pUId,
2862 PULONG pUnused)
2863{
2864 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
2865 HwDeviceExtension, ChildEnumInfo));
2866
2867 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
2868
2869 if (ChildEnumInfo->ChildIndex > 0)
2870 {
2871 if ((int)ChildEnumInfo->ChildIndex <= commonFromDeviceExt(pDevExt)->cDisplays)
2872 {
2873 *VideoChildType = Monitor;
2874 *pUId = ChildEnumInfo->ChildIndex;
2875
2876 return VIDEO_ENUM_MORE_DEVICES;
2877 }
2878 }
2879
2880 return ERROR_NO_MORE_DEVICES;
2881}
2882
2883
2884static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
2885{
2886 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
2887 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
2888
2889 if (pPrimaryDevExt)
2890 {
2891 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
2892
2893 if (req)
2894 {
2895 int rc = VbglGRPerform (&req->header);
2896
2897 if (RT_FAILURE(rc))
2898 {
2899 dprintf(("VBoxVideo::vbvaFlush: rc = %Rrc!\n", rc));
2900 }
2901 }
2902 }
2903
2904 return;
2905}
2906
2907int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
2908{
2909 int rc = VINF_SUCCESS;
2910
2911 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
2912
2913 /*
2914 * Query the VMMDev memory pointer. There we need VBVAMemory.
2915 */
2916 VMMDevMemory *pVMMDevMemory = NULL;
2917
2918 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
2919
2920 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
2921
2922 if (pDevExt->iDevice > 0)
2923 {
2924 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
2925
2926 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
2927 pDevExt->iDevice));
2928
2929 if ( ulEnable
2930 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
2931 {
2932 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2933 pVbvaResult->pfnFlush = vboxVbvaFlush;
2934 pVbvaResult->pvFlush = pDevExt;
2935 }
2936 else
2937 {
2938 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
2939 }
2940
2941 return rc;
2942 }
2943
2944 if (RT_SUCCESS(rc))
2945 {
2946 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
2947 if (pDevExt->u.primary.pvReqFlush == NULL)
2948 {
2949 VMMDevVideoAccelFlush *req = NULL;
2950
2951 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2952 sizeof (VMMDevVideoAccelFlush),
2953 VMMDevReq_VideoAccelFlush);
2954
2955 if (RT_SUCCESS (rc))
2956 {
2957 pDevExt->u.primary.pvReqFlush = req;
2958 }
2959 else
2960 {
2961 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Rrc!!!\n", rc));
2962 }
2963 }
2964 }
2965 else
2966 {
2967 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Rrc!!!\n", rc));
2968 }
2969
2970 if (RT_SUCCESS(rc))
2971 {
2972 ULONG ulEnabled = 0;
2973
2974 /*
2975 * Tell host that VBVA status is changed.
2976 */
2977 VMMDevVideoAccelEnable *req = NULL;
2978
2979 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2980 sizeof (VMMDevVideoAccelEnable),
2981 VMMDevReq_VideoAccelEnable);
2982
2983 if (RT_SUCCESS(rc))
2984 {
2985 req->u32Enable = ulEnable;
2986 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2987 req->fu32Status = 0;
2988
2989 rc = VbglGRPerform (&req->header);
2990
2991 if (RT_SUCCESS(rc))
2992 {
2993 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
2994 {
2995 /*
2996 * Initialize the result information and VBVA memory.
2997 */
2998 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
2999 {
3000 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
3001 pVbvaResult->pfnFlush = vboxVbvaFlush;
3002 pVbvaResult->pvFlush = pDevExt;
3003 ulEnabled = 1;
3004 }
3005 else
3006 {
3007 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
3008 }
3009
3010 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
3011 }
3012 else
3013 {
3014 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
3015
3016 /* Disable VBVA for old hosts. */
3017 req->u32Enable = 0;
3018 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
3019 req->fu32Status = 0;
3020
3021 VbglGRPerform (&req->header);
3022
3023 rc = VERR_NOT_SUPPORTED;
3024 }
3025 }
3026 else
3027 {
3028 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Rrc!\n", rc));
3029 }
3030
3031 VbglGRFree (&req->header);
3032 }
3033 else
3034 {
3035 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Rrc!\n", rc));
3036 }
3037
3038 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
3039 }
3040
3041 return rc;
3042}
3043#endif
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