VirtualBox

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

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

Don't disable the extended VBE mode when Windows want's to reset the graphics card. This simply did not work right since we did not reset the mode to the Windows boot mode but we set a mode <current width> x <current height> x 0 bpp which only caused an disturbing additional mode switch when chaning the display resolution. Tested with WinXP and Win2000 guests.

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