VirtualBox

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

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

more logging

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