1 /*
2 * PROJECT: ReactOS Bochs graphics card driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Bochs graphics card driver
5 * COPYRIGHT: Copyright 2022 Hervé Poussineau <hpoussin@reactos.org>
6 */
7
8 #include "bochsmp.h"
9
10 static const BOCHS_SIZE BochsAvailableResolutions[] = {
11 { 640, 480 }, // VGA
12 { 800, 600 }, // SVGA
13 { 1024, 600 }, // WSVGA
14 { 1024, 768 }, // XGA
15 { 1152, 864 }, // XGA+
16 { 1280, 720 }, // WXGA-H
17 { 1280, 768 }, // WXGA
18 { 1280, 960 }, // SXGA-
19 { 1280, 1024 }, // SXGA
20 { 1368, 768 }, // HD ready
21 { 1400, 1050 }, // SXGA+
22 { 1440, 900 }, // WSXGA
23 { 1600, 900 }, // HD+
24 { 1600, 1200 }, // UXGA
25 { 1680, 1050 }, // WSXGA+
26 { 1920, 1080 }, // FHD
27 { 2048, 1536 }, // QXGA
28 { 2560, 1440 }, // WQHD
29 { 2560, 1600 }, // WQXGA
30 { 2560, 2048 }, // QSXGA
31 { 2800, 2100 }, // QSXGA+
32 { 3200, 2400 }, // QUXGA
33 { 3840, 2160 }, // 4K UHD-1
34 };
35
36 CODE_SEG("PAGE")
37 static VOID
BochsFreeResources(_Inout_ PBOCHS_DEVICE_EXTENSION DeviceExtension)38 BochsFreeResources(
39 _Inout_ PBOCHS_DEVICE_EXTENSION DeviceExtension)
40 {
41 if (DeviceExtension->AvailableModeInfo)
42 {
43 VideoPortFreePool(DeviceExtension, DeviceExtension->AvailableModeInfo);
44 DeviceExtension->AvailableModeInfo = NULL;
45 }
46 }
47
48 CODE_SEG("PAGE")
49 static VOID
BochsWriteDispI(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_In_ ULONG Index,_In_ USHORT Value)50 BochsWriteDispI(
51 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
52 _In_ ULONG Index,
53 _In_ USHORT Value)
54 {
55 if (DeviceExtension->IoPorts.RangeInIoSpace)
56 {
57 VideoPortWritePortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_INDEX), Index);
58 VideoPortWritePortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_DATA), Value);
59 }
60 else
61 {
62 VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 0x500 + Index * 2), Value);
63 }
64 }
65
66 CODE_SEG("PAGE")
67 static USHORT
BochsReadDispI(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_In_ ULONG Index)68 BochsReadDispI(
69 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
70 _In_ ULONG Index)
71 {
72 if (DeviceExtension->IoPorts.RangeInIoSpace)
73 {
74 VideoPortWritePortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_INDEX), Index);
75 return VideoPortReadPortUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped - VBE_DISPI_IOPORT_INDEX + VBE_DISPI_IOPORT_DATA));
76 }
77 else
78 {
79 return VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 0x500 + Index * 2));
80 }
81 }
82
83 CODE_SEG("PAGE")
84 static BOOLEAN
BochsWriteDispIAndCheck(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_In_ ULONG Index,_In_ USHORT Value)85 BochsWriteDispIAndCheck(
86 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
87 _In_ ULONG Index,
88 _In_ USHORT Value)
89 {
90 BochsWriteDispI(DeviceExtension, Index, Value);
91 return BochsReadDispI(DeviceExtension, Index) == Value;
92 }
93
94 CODE_SEG("PAGE")
95 static BOOLEAN
BochsInitializeSuitableModeInfo(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_In_ ULONG PotentialModeCount)96 BochsInitializeSuitableModeInfo(
97 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
98 _In_ ULONG PotentialModeCount)
99 {
100 ULONG i, ModeCount = 0;
101
102 for (i = 0; i < ARRAYSIZE(BochsAvailableResolutions) && ModeCount < PotentialModeCount; i++)
103 {
104 if (BochsAvailableResolutions[i].XResolution > DeviceExtension->MaxXResolution)
105 continue;
106 if (BochsAvailableResolutions[i].YResolution > DeviceExtension->MaxYResolution)
107 continue;
108 if (BochsAvailableResolutions[i].XResolution * BochsAvailableResolutions[i].YResolution * 4 > DeviceExtension->VramSize64K * 64 * 1024)
109 continue;
110 DeviceExtension->AvailableModeInfo[ModeCount++] = BochsAvailableResolutions[i];
111 }
112
113 if (ModeCount == 0)
114 {
115 VideoDebugPrint((Error, "Bochs: no suitable modes available!\n"));
116 return FALSE;
117 }
118
119 DeviceExtension->AvailableModeCount = ModeCount;
120 return TRUE;
121 }
122
123 CODE_SEG("PAGE")
124 static BOOLEAN
BochsGetControllerInfo(_Inout_ PBOCHS_DEVICE_EXTENSION DeviceExtension)125 BochsGetControllerInfo(
126 _Inout_ PBOCHS_DEVICE_EXTENSION DeviceExtension)
127 {
128 USHORT Version;
129 WCHAR ChipType[5];
130 ULONG SizeInBytes;
131
132 /* Detect DISPI version */
133 for (Version = VBE_DISPI_ID5; Version >= VBE_DISPI_ID0; Version--)
134 {
135 if (BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_ID, Version))
136 break;
137 }
138 if (Version < VBE_DISPI_ID0)
139 {
140 VideoDebugPrint((Error, "Bochs: VBE extension signature incorrect\n"));
141 return FALSE;
142 }
143 VideoDebugPrint((Error, "Bochs: detected version 0x%04x\n", Version));
144 if (Version < VBE_DISPI_ID2)
145 {
146 /* Too old (no 32 bpp support, no linear frame buffer) */
147 VideoDebugPrint((Error, "Bochs: VBE extension too old (0x%04x)\n", Version));
148 return FALSE;
149 }
150
151 if (Version <= VBE_DISPI_ID2)
152 {
153 DeviceExtension->MaxXResolution = 1024;
154 DeviceExtension->MaxYResolution = 768;
155 }
156 else
157 {
158 BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, VBE_DISPI_GETCAPS);
159 DeviceExtension->MaxXResolution = BochsReadDispI(DeviceExtension, VBE_DISPI_INDEX_XRES);
160 DeviceExtension->MaxYResolution = BochsReadDispI(DeviceExtension, VBE_DISPI_INDEX_YRES);
161 BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
162 /* Workaround bug in QEMU bochs-display */
163 if (DeviceExtension->MaxXResolution == 0 && DeviceExtension->MaxYResolution == 0)
164 {
165 DeviceExtension->MaxXResolution = 1024;
166 DeviceExtension->MaxYResolution = 768;
167 }
168 }
169 if (Version < VBE_DISPI_ID4)
170 {
171 DeviceExtension->VramSize64K = 4 * 1024 / 64; /* 4 MB */
172 }
173 else if (Version == VBE_DISPI_ID4)
174 {
175 DeviceExtension->VramSize64K = 8 * 1024 / 64; /* 8 MB */
176 }
177 else
178 {
179 DeviceExtension->VramSize64K = BochsReadDispI(DeviceExtension, VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
180 }
181 VideoDebugPrint((Info, "Bochs: capabilities %dx%d (%d MB)\n",
182 DeviceExtension->MaxXResolution,
183 DeviceExtension->MaxYResolution,
184 DeviceExtension->VramSize64K * 64 / 1024));
185
186 /* Store information in registry */
187 #define HEX(c) (((c) >= 0 && (c) <= 9) ? (c) + L'0' : (c) - 10 + L'A')
188 ChipType[0] = HEX((Version >> 12) & 0xf);
189 ChipType[1] = HEX((Version >> 8) & 0xf);
190 ChipType[2] = HEX((Version >> 4) & 0xf);
191 ChipType[3] = HEX(Version & 0xf);
192 ChipType[4] = UNICODE_NULL;
193 VideoPortSetRegistryParameters(DeviceExtension, L"HardwareInformation.ChipType", ChipType, sizeof(ChipType));
194 SizeInBytes = DeviceExtension->VramSize64K * 64 * 1024;
195 VideoPortSetRegistryParameters(DeviceExtension, L"HardwareInformation.MemorySize", &SizeInBytes, sizeof(SizeInBytes));
196 return TRUE;
197 }
198
199 CODE_SEG("PAGE")
200 static VOID
BochsGetModeInfo(_In_ PBOCHS_SIZE AvailableModeInfo,_Out_ PVIDEO_MODE_INFORMATION ModeInfo,_In_ ULONG Index)201 BochsGetModeInfo(
202 _In_ PBOCHS_SIZE AvailableModeInfo,
203 _Out_ PVIDEO_MODE_INFORMATION ModeInfo,
204 _In_ ULONG Index)
205 {
206 VideoDebugPrint((Info, "Bochs: Filling details of mode #%d\n", Index));
207
208 ModeInfo->Length = sizeof(*ModeInfo);
209 ModeInfo->ModeIndex = Index;
210 ModeInfo->VisScreenWidth = AvailableModeInfo->XResolution;
211 ModeInfo->VisScreenHeight = AvailableModeInfo->YResolution;
212 ModeInfo->ScreenStride = AvailableModeInfo->XResolution * 4;
213 ModeInfo->NumberOfPlanes = 1;
214 ModeInfo->BitsPerPlane = 32;
215 ModeInfo->Frequency = 60;
216
217 /* 960 DPI appears to be common */
218 ModeInfo->XMillimeter = AvailableModeInfo->XResolution * 254 / 960;
219 ModeInfo->YMillimeter = AvailableModeInfo->YResolution * 254 / 960;
220 ModeInfo->NumberRedBits = 8;
221 ModeInfo->NumberGreenBits = 8;
222 ModeInfo->NumberBlueBits = 8;
223 ModeInfo->RedMask = 0xff0000;
224 ModeInfo->GreenMask = 0x00ff00;
225 ModeInfo->BlueMask = 0x0000ff;
226
227 ModeInfo->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
228 ModeInfo->VideoMemoryBitmapWidth = AvailableModeInfo->XResolution;
229 ModeInfo->VideoMemoryBitmapHeight = AvailableModeInfo->YResolution;
230 }
231
232 CODE_SEG("PAGE")
233 static BOOLEAN
BochsMapVideoMemory(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_In_ PVIDEO_MEMORY RequestedAddress,_Out_ PVIDEO_MEMORY_INFORMATION MapInformation,_Out_ PSTATUS_BLOCK StatusBlock)234 BochsMapVideoMemory(
235 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
236 _In_ PVIDEO_MEMORY RequestedAddress,
237 _Out_ PVIDEO_MEMORY_INFORMATION MapInformation,
238 _Out_ PSTATUS_BLOCK StatusBlock)
239 {
240 VP_STATUS Status;
241 PHYSICAL_ADDRESS VideoMemory;
242 ULONG MemSpace = VIDEO_MEMORY_SPACE_MEMORY;
243
244 VideoDebugPrint((Info, "Bochs: BochsMapVideoMemory Entry\n"));
245
246 VideoMemory = DeviceExtension->FrameBuffer.RangeStart;
247 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
248 MapInformation->VideoRamLength = 4 *
249 DeviceExtension->AvailableModeInfo[DeviceExtension->CurrentMode].XResolution *
250 DeviceExtension->AvailableModeInfo[DeviceExtension->CurrentMode].YResolution;
251
252 Status = VideoPortMapMemory(DeviceExtension,
253 VideoMemory,
254 &MapInformation->VideoRamLength,
255 &MemSpace,
256 &MapInformation->VideoRamBase);
257 if (Status != NO_ERROR)
258 {
259 VideoDebugPrint((Error, "BochsMapVideoMemory - VideoPortMapMemory failed status:%x\n", Status));
260 StatusBlock->Status = Status;
261 return FALSE;
262 }
263
264 MapInformation->FrameBufferBase = MapInformation->VideoRamBase;
265 MapInformation->FrameBufferLength = MapInformation->VideoRamLength;
266 StatusBlock->Information = sizeof(*MapInformation);
267 StatusBlock->Status = NO_ERROR;
268
269 VideoDebugPrint((Info, "Bochs:BochsMapVideoMemory Exit VideoRamBase: %p VideoRamLength: 0x%x PhysBasePtr: 0x%x\n",
270 MapInformation->VideoRamBase, MapInformation->VideoRamLength, (ULONG)VideoMemory.QuadPart));
271 return TRUE;
272 }
273
274 CODE_SEG("PAGE")
275 static BOOLEAN NTAPI
BochsUnmapVideoMemory(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_In_ PVIDEO_MEMORY VideoMemory,_Out_ PSTATUS_BLOCK StatusBlock)276 BochsUnmapVideoMemory(
277 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
278 _In_ PVIDEO_MEMORY VideoMemory,
279 _Out_ PSTATUS_BLOCK StatusBlock)
280 {
281 VP_STATUS Status;
282
283 VideoDebugPrint((Info, "Bochs: BochsUnmapVideoMemory Entry VideoRamBase:%p\n", VideoMemory->RequestedVirtualAddress));
284
285 Status = VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
286 if (Status != NO_ERROR)
287 {
288 VideoDebugPrint((Error, "Bochs: BochsUnmapVideoMemory Failed to unmap memory:%p Status:%x\n",
289 VideoMemory->RequestedVirtualAddress,
290 Status));
291 }
292
293 StatusBlock->Status = Status;
294
295 VideoDebugPrint((Info, "Bochs: BochsUnmapVideoMemory Exit status:%x\n", Status));
296 return (Status == NO_ERROR);
297 }
298
299 CODE_SEG("PAGE")
300 static BOOLEAN
BochsQueryNumAvailableModes(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_Out_ PVIDEO_NUM_MODES AvailableModes,_Out_ PSTATUS_BLOCK StatusBlock)301 BochsQueryNumAvailableModes(
302 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
303 _Out_ PVIDEO_NUM_MODES AvailableModes,
304 _Out_ PSTATUS_BLOCK StatusBlock)
305 {
306 AvailableModes->NumModes = DeviceExtension->AvailableModeCount;
307 AvailableModes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
308
309 StatusBlock->Information = sizeof(*AvailableModes);
310 StatusBlock->Status = NO_ERROR;
311 return TRUE;
312 }
313
314 CODE_SEG("PAGE")
315 static BOOLEAN
BochsQueryAvailableModes(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_Out_ PVIDEO_MODE_INFORMATION ReturnedModes,_Out_ PSTATUS_BLOCK StatusBlock)316 BochsQueryAvailableModes(
317 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
318 _Out_ PVIDEO_MODE_INFORMATION ReturnedModes,
319 _Out_ PSTATUS_BLOCK StatusBlock)
320 {
321 ULONG Count;
322 PBOCHS_SIZE AvailableModeInfo;
323 PVIDEO_MODE_INFORMATION ModeInfo;
324
325 for (Count = 0, AvailableModeInfo = DeviceExtension->AvailableModeInfo, ModeInfo = ReturnedModes;
326 Count < DeviceExtension->AvailableModeCount;
327 Count++, AvailableModeInfo++, ModeInfo++)
328 {
329 VideoPortZeroMemory(ModeInfo, sizeof(*ModeInfo));
330 BochsGetModeInfo(AvailableModeInfo, ModeInfo, Count);
331 }
332
333 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION) * DeviceExtension->AvailableModeCount;
334 StatusBlock->Status = NO_ERROR;
335
336 return TRUE;
337 }
338
339 CODE_SEG("PAGE")
340 static BOOLEAN
BochsSetCurrentMode(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_In_ PVIDEO_MODE RequestedMode,_Out_ PSTATUS_BLOCK StatusBlock)341 BochsSetCurrentMode(
342 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
343 _In_ PVIDEO_MODE RequestedMode,
344 _Out_ PSTATUS_BLOCK StatusBlock)
345 {
346 PBOCHS_SIZE AvailableModeInfo;
347 /* Mask the two high-order bits, which can be set to request special behavior */
348 ULONG ModeRequested = RequestedMode->RequestedMode & 0x3fffffff;
349 BOOLEAN Ret;
350
351 VideoDebugPrint((Info, "Bochs:BochsSetCurrentMode Entry\n"));
352
353 if (ModeRequested >= DeviceExtension->AvailableModeCount)
354 {
355 VideoDebugPrint((Error, "Bochs: set current mode - invalid parameter\n"));
356 StatusBlock->Status = ERROR_INVALID_PARAMETER;
357 return FALSE;
358 }
359
360 AvailableModeInfo = &DeviceExtension->AvailableModeInfo[ModeRequested];
361
362 /* Set the mode characteristics */
363 BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
364 Ret = BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_XRES, AvailableModeInfo->XResolution) &&
365 BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_YRES, AvailableModeInfo->YResolution) &&
366 BochsWriteDispIAndCheck(DeviceExtension, VBE_DISPI_INDEX_BPP, 32);
367 /* Always enable screen, even if display settings change failed */
368 BochsWriteDispI(DeviceExtension, VBE_DISPI_INDEX_ENABLE, VBE_DISPI_LFB_ENABLED | VBE_DISPI_ENABLED);
369 if (!Ret)
370 {
371 VideoDebugPrint((Error, "Bochs: failed to change mode\n"));
372 return FALSE;
373 }
374
375 /* Enable VGA (QEMU secondary-vga disables it by default) */
376 if (!DeviceExtension->IoPorts.RangeInIoSpace)
377 {
378 /* Discard AR flip-flip */
379 (VOID)VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 0x41A));
380 /* Enable display */
381 VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->IoPorts.Mapped + 0x400), 0x20);
382 }
383
384 DeviceExtension->CurrentMode = (USHORT)ModeRequested;
385 StatusBlock->Status = NO_ERROR;
386
387 VideoDebugPrint((Info, "Bochs:BochsSetCurrentMode Exit Mode:%d\n", ModeRequested));
388 return TRUE;
389 }
390
391 CODE_SEG("PAGE")
392 static BOOLEAN
BochsQueryCurrentMode(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_Out_ PVIDEO_MODE_INFORMATION VideoModeInfo,_Out_ PSTATUS_BLOCK StatusBlock)393 BochsQueryCurrentMode(
394 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
395 _Out_ PVIDEO_MODE_INFORMATION VideoModeInfo,
396 _Out_ PSTATUS_BLOCK StatusBlock)
397 {
398 PBOCHS_SIZE AvailableModeInfo;
399
400 if (DeviceExtension->CurrentMode > DeviceExtension->AvailableModeCount)
401 {
402 StatusBlock->Status = ERROR_INVALID_PARAMETER;
403 return FALSE;
404 }
405
406 AvailableModeInfo = &DeviceExtension->AvailableModeInfo[DeviceExtension->CurrentMode];
407 VideoPortZeroMemory(VideoModeInfo, sizeof(*VideoModeInfo));
408 BochsGetModeInfo(AvailableModeInfo, VideoModeInfo, DeviceExtension->CurrentMode);
409
410 StatusBlock->Information = sizeof(*VideoModeInfo);
411 StatusBlock->Status = NO_ERROR;
412 return TRUE;
413 }
414
415 CODE_SEG("PAGE")
416 static BOOLEAN
BochsResetDevice(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_Out_ PSTATUS_BLOCK StatusBlock)417 BochsResetDevice(
418 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
419 _Out_ PSTATUS_BLOCK StatusBlock)
420 {
421 VideoDebugPrint((Info, "Bochs:BochsResetDevice Entry\n"));
422
423 StatusBlock->Status = NO_ERROR;
424
425 VideoDebugPrint((Info, "Bochs:BochsResetDevice Exit\n"));
426 return TRUE;
427 }
428
429 CODE_SEG("PAGE")
430 static BOOLEAN
BochsGetChildState(_In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,_Out_ PULONG pChildState,_Out_ PSTATUS_BLOCK StatusBlock)431 BochsGetChildState(
432 _In_ PBOCHS_DEVICE_EXTENSION DeviceExtension,
433 _Out_ PULONG pChildState,
434 _Out_ PSTATUS_BLOCK StatusBlock)
435 {
436 *pChildState = VIDEO_CHILD_ACTIVE;
437
438 StatusBlock->Information = sizeof(*pChildState);
439 StatusBlock->Status = NO_ERROR;
440 return TRUE;
441 }
442
443 CODE_SEG("PAGE")
444 VP_STATUS NTAPI
BochsFindAdapter(_In_ PVOID HwDeviceExtension,_In_ PVOID HwContext,_In_ PWSTR ArgumentString,_In_ PVIDEO_PORT_CONFIG_INFO ConfigInfo,_In_ PUCHAR Again)445 BochsFindAdapter(
446 _In_ PVOID HwDeviceExtension,
447 _In_ PVOID HwContext,
448 _In_ PWSTR ArgumentString,
449 _In_ PVIDEO_PORT_CONFIG_INFO ConfigInfo,
450 _In_ PUCHAR Again)
451 {
452 PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
453 VIDEO_ACCESS_RANGE AccessRanges[2] = {0};
454
455 if (ConfigInfo->Length < sizeof(*ConfigInfo))
456 return ERROR_INVALID_PARAMETER;
457
458 if (VideoPortGetAccessRanges(DeviceExtension, 0, NULL, ARRAYSIZE(AccessRanges), AccessRanges, NULL, NULL, NULL) != NO_ERROR)
459 {
460 VideoDebugPrint((Error, "Bochs: failed to get access ranges\n"));
461 return ERROR_DEV_NOT_EXIST;
462 }
463
464 /* Framebuffer */
465 DeviceExtension->FrameBuffer.RangeStart = AccessRanges[0].RangeStart;
466 DeviceExtension->FrameBuffer.RangeLength = AccessRanges[0].RangeLength;
467 DeviceExtension->FrameBuffer.RangeInIoSpace = AccessRanges[0].RangeInIoSpace;
468
469 /* I/O ports */
470 if (AccessRanges[1].RangeLength == 0)
471 {
472 /* Set default values */
473 AccessRanges[1].RangeStart.LowPart = VBE_DISPI_IOPORT_INDEX;
474 AccessRanges[1].RangeLength = 2;
475 AccessRanges[1].RangeInIoSpace = TRUE;
476 if (VideoPortVerifyAccessRanges(DeviceExtension, 1, &AccessRanges[1]) != NO_ERROR)
477 {
478 VideoDebugPrint((Error, "Bochs: failed to claim I/O range 0x%x-0x%x\n",
479 VBE_DISPI_IOPORT_INDEX,
480 VBE_DISPI_IOPORT_INDEX + 1));
481 return ERROR_DEV_NOT_EXIST;
482 }
483 }
484 else if (AccessRanges[1].RangeLength != 0x1000)
485 {
486 VideoDebugPrint((Error, "Bochs: invalid access ranges (size 0x%x)\n", AccessRanges[1].RangeLength));
487 return ERROR_DEV_NOT_EXIST;
488 }
489 DeviceExtension->IoPorts.RangeStart = AccessRanges[1].RangeStart;
490 DeviceExtension->IoPorts.RangeLength = AccessRanges[1].RangeLength;
491 DeviceExtension->IoPorts.RangeInIoSpace = AccessRanges[1].RangeInIoSpace;
492
493 DeviceExtension->IoPorts.Mapped = VideoPortGetDeviceBase(DeviceExtension,
494 DeviceExtension->IoPorts.RangeStart,
495 DeviceExtension->IoPorts.RangeLength,
496 DeviceExtension->IoPorts.RangeInIoSpace
497 ? VIDEO_MEMORY_SPACE_IO
498 : VIDEO_MEMORY_SPACE_MEMORY);
499 if (!DeviceExtension->IoPorts.Mapped)
500 {
501 VideoDebugPrint((Error, "Bochs: failed to map dispi interface\n"));
502 return ERROR_DEV_NOT_EXIST;
503 }
504 VideoDebugPrint((Info, "Bochs: address 0x%x mapped to 0x%p\n",
505 DeviceExtension->IoPorts.RangeStart.LowPart,
506 DeviceExtension->IoPorts.Mapped));
507
508 return NO_ERROR;
509 }
510
511 CODE_SEG("PAGE")
512 BOOLEAN NTAPI
BochsInitialize(_In_ PVOID HwDeviceExtension)513 BochsInitialize(
514 _In_ PVOID HwDeviceExtension)
515 {
516 ULONG PotentialModeCount = 0;
517 PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
518
519 VideoDebugPrint((Info, "Bochs: BochsInitialize\n"));
520
521 if (!BochsGetControllerInfo(DeviceExtension))
522 {
523 BochsFreeResources(DeviceExtension);
524 return FALSE;
525 }
526
527 PotentialModeCount = ARRAYSIZE(BochsAvailableResolutions);
528 DeviceExtension->AvailableModeInfo = VideoPortAllocatePool(HwDeviceExtension,
529 VpPagedPool,
530 PotentialModeCount * sizeof(BOCHS_SIZE),
531 BOCHS_TAG);
532 if (!DeviceExtension->AvailableModeInfo)
533 {
534 VideoDebugPrint((Error, "Bochs: insufficient resources\n"));
535 BochsFreeResources(DeviceExtension);
536 return FALSE;
537 }
538
539 if (!BochsInitializeSuitableModeInfo(DeviceExtension, PotentialModeCount))
540 {
541 BochsFreeResources(DeviceExtension);
542 return FALSE;
543 }
544
545 return TRUE;
546 }
547
548 CODE_SEG("PAGE")
549 BOOLEAN NTAPI
BochsStartIO(_In_ PVOID HwDeviceExtension,_Inout_ PVIDEO_REQUEST_PACKET RequestPacket)550 BochsStartIO(
551 _In_ PVOID HwDeviceExtension,
552 _Inout_ PVIDEO_REQUEST_PACKET RequestPacket)
553 {
554 PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
555
556 VideoDebugPrint((Info, "Bochs: BochsStartIO\n"));
557 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
558
559 switch (RequestPacket->IoControlCode)
560 {
561 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
562 {
563 VideoDebugPrint((Info, "BochsStartIO - Map video memory\n"));
564 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
565 {
566 VideoDebugPrint((Error, "BochsStartIO - invalid input parameter\n"));
567 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
568 return FALSE;
569 }
570 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION))
571 {
572 VideoDebugPrint((Error, "BochsStartIO - Insufficent output buffer\n"));
573 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
574 return FALSE;
575 }
576 return BochsMapVideoMemory(DeviceExtension,
577 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
578 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
579 RequestPacket->StatusBlock);
580 }
581
582 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
583 {
584 VideoDebugPrint((Info, "BochsStartIO - Unmap video memory\n"));
585 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
586 {
587 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
588 return FALSE;
589 }
590 return BochsUnmapVideoMemory(DeviceExtension,
591 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
592 RequestPacket->StatusBlock);
593 }
594
595 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
596 {
597 VideoDebugPrint((Info, "BochsStartIO - Query num available modes\n"));
598 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
599 {
600 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
601 return FALSE;
602 }
603 return BochsQueryNumAvailableModes(DeviceExtension,
604 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
605 RequestPacket->StatusBlock);
606 }
607
608 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
609 {
610 VideoDebugPrint((Info, "BochsStartIO - Query available modes\n"));
611 if (RequestPacket->OutputBufferLength < DeviceExtension->AvailableModeCount * sizeof(VIDEO_MODE_INFORMATION))
612 {
613 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
614 return FALSE;
615 }
616 return BochsQueryAvailableModes(DeviceExtension,
617 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
618 RequestPacket->StatusBlock);
619 }
620
621 case IOCTL_VIDEO_SET_CURRENT_MODE:
622 {
623 VideoDebugPrint((Info, "BochsStartIO - Set current mode\n"));
624 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
625 {
626 VideoDebugPrint((Error, "Bochs: set current mode - invalid parameter\n"));
627 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
628 return FALSE;
629 }
630 return BochsSetCurrentMode(DeviceExtension,
631 (PVIDEO_MODE)RequestPacket->InputBuffer,
632 RequestPacket->StatusBlock);
633 }
634
635 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
636 {
637 VideoDebugPrint((Info, "BochsStartIO - Query current mode\n"));
638 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
639 {
640 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
641 return FALSE;
642 }
643 return BochsQueryCurrentMode(DeviceExtension,
644 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
645 RequestPacket->StatusBlock);
646 }
647
648 case IOCTL_VIDEO_RESET_DEVICE:
649 {
650 VideoDebugPrint((Info, "BochsStartIO - Reset device\n"));
651 return BochsResetDevice(DeviceExtension,
652 RequestPacket->StatusBlock);
653 }
654
655 case IOCTL_VIDEO_GET_CHILD_STATE:
656 {
657 VideoDebugPrint((Info, "BochsStartIO - Get child state\n"));
658 if (RequestPacket->OutputBufferLength < sizeof(ULONG))
659 {
660 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
661 return FALSE;
662 }
663 return BochsGetChildState(DeviceExtension,
664 (PULONG)RequestPacket->OutputBuffer,
665 RequestPacket->StatusBlock);
666 }
667
668 default:
669 {
670 VideoDebugPrint((Warn, "BochsStartIO - Unknown IOCTL - 0x%08x\n",
671 RequestPacket->IoControlCode));
672 break;
673 }
674 }
675
676 return FALSE;
677 }
678
679 CODE_SEG("PAGE")
680 VP_STATUS NTAPI
BochsSetPowerState(_In_ PVOID HwDeviceExtension,_In_ ULONG HwId,_In_ PVIDEO_POWER_MANAGEMENT VideoPowerControl)681 BochsSetPowerState(
682 _In_ PVOID HwDeviceExtension,
683 _In_ ULONG HwId,
684 _In_ PVIDEO_POWER_MANAGEMENT VideoPowerControl)
685 {
686 return NO_ERROR;
687 }
688
689 CODE_SEG("PAGE")
690 VP_STATUS NTAPI
BochsGetPowerState(_In_ PVOID HwDeviceExtension,_In_ ULONG HwId,_Out_ PVIDEO_POWER_MANAGEMENT VideoPowerControl)691 BochsGetPowerState(
692 _In_ PVOID HwDeviceExtension,
693 _In_ ULONG HwId,
694 _Out_ PVIDEO_POWER_MANAGEMENT VideoPowerControl)
695 {
696 return ERROR_DEVICE_REINITIALIZATION_NEEDED;
697 }
698
699 CODE_SEG("PAGE")
700 VP_STATUS NTAPI
BochsGetVideoChildDescriptor(_In_ PVOID HwDeviceExtension,_In_ PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,_Out_ PVIDEO_CHILD_TYPE VideoChildType,_Out_ PUCHAR pChildDescriptor,_Out_ PULONG UId,_Out_ PULONG pUnused)701 BochsGetVideoChildDescriptor(
702 _In_ PVOID HwDeviceExtension,
703 _In_ PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
704 _Out_ PVIDEO_CHILD_TYPE VideoChildType,
705 _Out_ PUCHAR pChildDescriptor,
706 _Out_ PULONG UId,
707 _Out_ PULONG pUnused)
708 {
709 PBOCHS_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
710
711 VideoDebugPrint((Info, "Bochs: BochsGetVideoChildDescriptor Entry\n"));
712
713 if (ChildEnumInfo->Size < sizeof(*VideoChildType))
714 return VIDEO_ENUM_NO_MORE_DEVICES;
715
716 if (ChildEnumInfo->ChildIndex == 0)
717 {
718 /* Ignore ACPI enumerations */
719 return VIDEO_ENUM_INVALID_DEVICE;
720 }
721
722 *pUnused = 0;
723 if (ChildEnumInfo->ChildIndex == DISPLAY_ADAPTER_HW_ID)
724 {
725 *VideoChildType = VideoChip;
726 return VIDEO_ENUM_MORE_DEVICES;
727 }
728
729 if (ChildEnumInfo->ChildIndex != 1)
730 return VIDEO_ENUM_NO_MORE_DEVICES;
731
732 *UId = 0;
733 *VideoChildType = Monitor;
734
735 if (pChildDescriptor &&
736 ChildEnumInfo->ChildDescriptorSize >= VBE_EDID_SIZE &&
737 !DeviceExtension->IoPorts.RangeInIoSpace)
738 {
739 memcpy(pChildDescriptor,
740 DeviceExtension->IoPorts.Mapped,
741 VBE_EDID_SIZE);
742 }
743
744 VideoDebugPrint((Info, "Bochs: BochsGetVideoChildDescriptor Exit Uid:%d\n", ChildEnumInfo->ChildIndex));
745
746 return VIDEO_ENUM_MORE_DEVICES;
747 }
748
749 ULONG NTAPI
DriverEntry(PVOID Context1,PVOID Context2)750 DriverEntry(PVOID Context1, PVOID Context2)
751 {
752 VIDEO_HW_INITIALIZATION_DATA VideoInitData;
753
754 VideoDebugPrint((Info, "Bochs: DriverEntry\n"));
755 VideoPortZeroMemory(&VideoInitData, sizeof(VideoInitData));
756 VideoInitData.HwInitDataSize = sizeof(VideoInitData);
757 VideoInitData.HwFindAdapter = BochsFindAdapter;
758 VideoInitData.HwInitialize = BochsInitialize;
759 VideoInitData.HwStartIO = BochsStartIO;
760 VideoInitData.HwDeviceExtensionSize = sizeof(BOCHS_DEVICE_EXTENSION);
761 VideoInitData.HwSetPowerState = BochsSetPowerState;
762 VideoInitData.HwGetPowerState = BochsGetPowerState;
763 VideoInitData.HwGetVideoChildDescriptor = BochsGetVideoChildDescriptor;
764
765 return VideoPortInitialize(Context1, Context2, &VideoInitData, NULL);
766 }
767