]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/QemuVideoDxe/Driver.c
OvmfPkg/QemuVideoDxe: VMWare SVGA device support
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Driver.c
CommitLineData
eaf4f336 1/** @file\r
2 This driver is a sample implementation of the Graphics Output Protocol for\r
3 the QEMU (Cirrus Logic 5446) video controller.\r
4\r
5 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
6\r
7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
c137d950 17#include <IndustryStandard/VmwareSvga.h>\r
cdb4f5dc 18#include <IndustryStandard/Acpi.h>\r
c137d950
PDJ
19#include "Qemu.h"\r
20#include "UnalignedIoInternal.h"\r
eaf4f336 21\r
22EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {\r
23 QemuVideoControllerDriverSupported,\r
24 QemuVideoControllerDriverStart,\r
25 QemuVideoControllerDriverStop,\r
26 0x10,\r
27 NULL,\r
28 NULL\r
29};\r
30\r
212aac55 31QEMU_VIDEO_CARD gQemuVideoCardList[] = {\r
32 {\r
33 CIRRUS_LOGIC_VENDOR_ID,\r
34 CIRRUS_LOGIC_5430_DEVICE_ID,\r
35 QEMU_VIDEO_CIRRUS_5430,\r
36 L"Cirrus 5430"\r
37 },{\r
38 CIRRUS_LOGIC_VENDOR_ID,\r
39 CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,\r
40 QEMU_VIDEO_CIRRUS_5430,\r
41 L"Cirrus 5430"\r
42 },{\r
43 CIRRUS_LOGIC_VENDOR_ID,\r
44 CIRRUS_LOGIC_5446_DEVICE_ID,\r
45 QEMU_VIDEO_CIRRUS_5446,\r
46 L"Cirrus 5446"\r
54f9b9ac 47 },{\r
48 0x1234,\r
49 0x1111,\r
cdb4f5dc 50 QEMU_VIDEO_BOCHS_MMIO,\r
54f9b9ac 51 L"QEMU Standard VGA"\r
52 },{\r
53 0x1b36,\r
54 0x0100,\r
55 QEMU_VIDEO_BOCHS,\r
56 L"QEMU QXL VGA"\r
94210dc9
GH
57 },{\r
58 0x1af4,\r
59 0x1050,\r
60 QEMU_VIDEO_BOCHS_MMIO,\r
61 L"QEMU VirtIO VGA"\r
c137d950
PDJ
62 },{\r
63 VMWARE_PCI_VENDOR_ID_VMWARE,\r
64 VMWARE_PCI_DEVICE_ID_VMWARE_SVGA2,\r
65 QEMU_VIDEO_VMWARE_SVGA,\r
66 L"QEMU VMWare SVGA"\r
212aac55 67 },{\r
68 0 /* end of list */\r
69 }\r
70};\r
71\r
72static QEMU_VIDEO_CARD*\r
73QemuVideoDetect(\r
74 IN UINT16 VendorId,\r
75 IN UINT16 DeviceId\r
76 )\r
77{\r
78 UINTN Index = 0;\r
79\r
80 while (gQemuVideoCardList[Index].VendorId != 0) {\r
81 if (gQemuVideoCardList[Index].VendorId == VendorId &&\r
82 gQemuVideoCardList[Index].DeviceId == DeviceId) {\r
83 return gQemuVideoCardList + Index;\r
84 }\r
85 Index++;\r
86 }\r
87 return NULL;\r
88}\r
89\r
eaf4f336 90/**\r
91 Check if this device is supported.\r
92\r
93 @param This The driver binding protocol.\r
94 @param Controller The controller handle to check.\r
95 @param RemainingDevicePath The remaining device path.\r
96\r
97 @retval EFI_SUCCESS The bus supports this controller.\r
98 @retval EFI_UNSUPPORTED This device isn't supported.\r
99\r
100**/\r
101EFI_STATUS\r
102EFIAPI\r
103QemuVideoControllerDriverSupported (\r
104 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
105 IN EFI_HANDLE Controller,\r
106 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
107 )\r
108{\r
109 EFI_STATUS Status;\r
110 EFI_PCI_IO_PROTOCOL *PciIo;\r
111 PCI_TYPE00 Pci;\r
212aac55 112 QEMU_VIDEO_CARD *Card;\r
eaf4f336 113\r
114 //\r
115 // Open the PCI I/O Protocol\r
116 //\r
117 Status = gBS->OpenProtocol (\r
118 Controller,\r
119 &gEfiPciIoProtocolGuid,\r
120 (VOID **) &PciIo,\r
121 This->DriverBindingHandle,\r
122 Controller,\r
123 EFI_OPEN_PROTOCOL_BY_DRIVER\r
124 );\r
125 if (EFI_ERROR (Status)) {\r
126 return Status;\r
127 }\r
128\r
129 //\r
130 // Read the PCI Configuration Header from the PCI Device\r
131 //\r
132 Status = PciIo->Pci.Read (\r
133 PciIo,\r
134 EfiPciIoWidthUint32,\r
135 0,\r
136 sizeof (Pci) / sizeof (UINT32),\r
137 &Pci\r
138 );\r
139 if (EFI_ERROR (Status)) {\r
140 goto Done;\r
141 }\r
142\r
143 Status = EFI_UNSUPPORTED;\r
442c2ab8
LE
144 if (!IS_PCI_VGA (&Pci)) {\r
145 goto Done;\r
146 }\r
212aac55 147 Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
148 if (Card != NULL) {\r
149 DEBUG ((EFI_D_INFO, "QemuVideo: %s detected\n", Card->Name));\r
150 Status = EFI_SUCCESS;\r
eaf4f336 151 }\r
152\r
153Done:\r
154 //\r
155 // Close the PCI I/O Protocol\r
156 //\r
157 gBS->CloseProtocol (\r
158 Controller,\r
159 &gEfiPciIoProtocolGuid,\r
160 This->DriverBindingHandle,\r
161 Controller\r
162 );\r
163\r
164 return Status;\r
165}\r
166\r
167/**\r
168 Start to process the controller.\r
169\r
170 @param This The USB bus driver binding instance.\r
171 @param Controller The controller to check.\r
172 @param RemainingDevicePath The remaining device patch.\r
173\r
174 @retval EFI_SUCCESS The controller is controlled by the usb bus.\r
175 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb\r
176 bus.\r
177 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
178\r
179**/\r
180EFI_STATUS\r
181EFIAPI\r
182QemuVideoControllerDriverStart (\r
183 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
184 IN EFI_HANDLE Controller,\r
185 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
186 )\r
187{\r
9c08bbe5 188 EFI_TPL OldTpl;\r
cdb4f5dc 189 EFI_STATUS Status;\r
190 QEMU_VIDEO_PRIVATE_DATA *Private;\r
b37bcfd6 191 BOOLEAN IsQxl;\r
cdb4f5dc 192 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
42d0cad7 193 ACPI_ADR_DEVICE_PATH AcpiDeviceNode;\r
cdb4f5dc 194 PCI_TYPE00 Pci;\r
195 QEMU_VIDEO_CARD *Card;\r
4374c2e5 196 EFI_PCI_IO_PROTOCOL *ChildPciIo;\r
54f9b9ac 197\r
9c08bbe5
LE
198 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
199\r
eaf4f336 200 //\r
201 // Allocate Private context data for GOP inteface.\r
202 //\r
203 Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));\r
204 if (Private == NULL) {\r
9c08bbe5
LE
205 Status = EFI_OUT_OF_RESOURCES;\r
206 goto RestoreTpl;\r
eaf4f336 207 }\r
208\r
209 //\r
210 // Set up context record\r
211 //\r
212 Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;\r
eaf4f336 213\r
214 //\r
215 // Open PCI I/O Protocol\r
216 //\r
217 Status = gBS->OpenProtocol (\r
218 Controller,\r
219 &gEfiPciIoProtocolGuid,\r
220 (VOID **) &Private->PciIo,\r
221 This->DriverBindingHandle,\r
222 Controller,\r
223 EFI_OPEN_PROTOCOL_BY_DRIVER\r
224 );\r
225 if (EFI_ERROR (Status)) {\r
d89186bc 226 goto FreePrivate;\r
eaf4f336 227 }\r
228\r
212aac55 229 //\r
230 // Read the PCI Configuration Header from the PCI Device\r
231 //\r
232 Status = Private->PciIo->Pci.Read (\r
233 Private->PciIo,\r
234 EfiPciIoWidthUint32,\r
235 0,\r
236 sizeof (Pci) / sizeof (UINT32),\r
237 &Pci\r
238 );\r
239 if (EFI_ERROR (Status)) {\r
d89186bc 240 goto ClosePciIo;\r
212aac55 241 }\r
242\r
d89186bc
LE
243 //\r
244 // Determine card variant.\r
245 //\r
212aac55 246 Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
247 if (Card == NULL) {\r
248 Status = EFI_DEVICE_ERROR;\r
d89186bc 249 goto ClosePciIo;\r
212aac55 250 }\r
251 Private->Variant = Card->Variant;\r
c137d950 252 Private->FrameBufferVramBarIndex = PCI_BAR_IDX0;\r
212aac55 253\r
b37bcfd6
LE
254 //\r
255 // IsQxl is based on the detected Card->Variant, which at a later point might\r
256 // not match Private->Variant.\r
257 //\r
258 IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS);\r
259\r
eaf4f336 260 //\r
261 // Save original PCI attributes\r
262 //\r
263 Status = Private->PciIo->Attributes (\r
264 Private->PciIo,\r
265 EfiPciIoAttributeOperationGet,\r
266 0,\r
267 &Private->OriginalPciAttributes\r
268 );\r
269\r
270 if (EFI_ERROR (Status)) {\r
d89186bc 271 goto ClosePciIo;\r
eaf4f336 272 }\r
eaf4f336 273\r
d89186bc
LE
274 //\r
275 // Set new PCI attributes\r
276 //\r
eaf4f336 277 Status = Private->PciIo->Attributes (\r
278 Private->PciIo,\r
279 EfiPciIoAttributeOperationEnable,\r
280 EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,\r
281 NULL\r
282 );\r
283 if (EFI_ERROR (Status)) {\r
d89186bc 284 goto ClosePciIo;\r
eaf4f336 285 }\r
286\r
cdb4f5dc 287 //\r
288 // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).\r
289 //\r
290 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
d89186bc
LE
291 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;\r
292\r
cdb4f5dc 293 Status = Private->PciIo->GetBarAttributes (\r
294 Private->PciIo,\r
295 PCI_BAR_IDX2,\r
296 NULL,\r
297 (VOID**) &MmioDesc\r
298 );\r
299 if (EFI_ERROR (Status) ||\r
300 MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
301 DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));\r
302 Private->Variant = QEMU_VIDEO_BOCHS;\r
303 } else {\r
304 DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",\r
305 MmioDesc->AddrRangeMin));\r
306 }\r
5cdb96fa
LE
307\r
308 if (!EFI_ERROR (Status)) {\r
309 FreePool (MmioDesc);\r
310 }\r
cdb4f5dc 311 }\r
312\r
54f9b9ac 313 //\r
314 // Check if accessing the bochs interface works.\r
315 //\r
cdb4f5dc 316 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||\r
317 Private->Variant == QEMU_VIDEO_BOCHS) {\r
54f9b9ac 318 UINT16 BochsId;\r
319 BochsId = BochsRead(Private, VBE_DISPI_INDEX_ID);\r
320 if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {\r
321 DEBUG ((EFI_D_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));\r
322 Status = EFI_DEVICE_ERROR;\r
d89186bc 323 goto RestoreAttributes;\r
54f9b9ac 324 }\r
325 }\r
326\r
c137d950
PDJ
327 //\r
328 // Check if accessing Vmware SVGA interface works\r
329 //\r
330 if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) {\r
331 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *IoDesc;\r
332 UINT32 TargetId;\r
333 UINT32 SvgaIdRead;\r
334\r
335 IoDesc = NULL;\r
336 Status = Private->PciIo->GetBarAttributes (\r
337 Private->PciIo,\r
338 PCI_BAR_IDX0,\r
339 NULL,\r
340 (VOID**) &IoDesc\r
341 );\r
342 if (EFI_ERROR (Status) ||\r
343 IoDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_IO ||\r
344 IoDesc->AddrRangeMin > MAX_UINT16 + 1 - (VMWARE_SVGA_VALUE_PORT + 4)) {\r
345 if (IoDesc != NULL) {\r
346 FreePool (IoDesc);\r
347 }\r
348 Status = EFI_DEVICE_ERROR;\r
349 goto RestoreAttributes;\r
350 }\r
351 Private->VmwareSvgaBasePort = (UINT16) IoDesc->AddrRangeMin;\r
352 FreePool (IoDesc);\r
353\r
354 TargetId = VMWARE_SVGA_ID_2;\r
355 while (TRUE) {\r
356 VmwareSvgaWrite (Private, VmwareSvgaRegId, TargetId);\r
357 SvgaIdRead = VmwareSvgaRead (Private, VmwareSvgaRegId);\r
358 if ((SvgaIdRead == TargetId) || (TargetId <= VMWARE_SVGA_ID_0)) {\r
359 break;\r
360 }\r
361 TargetId--;\r
362 }\r
363\r
364 if (SvgaIdRead != TargetId) {\r
365 DEBUG ((\r
366 DEBUG_ERROR,\r
367 "QemuVideo: QEMU_VIDEO_VMWARE_SVGA ID mismatch "\r
368 "(got 0x%x, base address 0x%x)\n",\r
369 SvgaIdRead,\r
370 Private->VmwareSvgaBasePort\r
371 ));\r
372 Status = EFI_DEVICE_ERROR;\r
373 goto RestoreAttributes;\r
374 }\r
375\r
376 Private->FrameBufferVramBarIndex = PCI_BAR_IDX1;\r
377 }\r
378\r
eaf4f336 379 //\r
380 // Get ParentDevicePath\r
381 //\r
382 Status = gBS->HandleProtocol (\r
383 Controller,\r
384 &gEfiDevicePathProtocolGuid,\r
385 (VOID **) &ParentDevicePath\r
386 );\r
387 if (EFI_ERROR (Status)) {\r
d89186bc 388 goto RestoreAttributes;\r
eaf4f336 389 }\r
390\r
391 //\r
392 // Set Gop Device Path\r
393 //\r
42d0cad7
LE
394 ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));\r
395 AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
396 AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
397 AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);\r
398 SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));\r
399\r
400 Private->GopDevicePath = AppendDevicePathNode (\r
401 ParentDevicePath,\r
402 (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode\r
403 );\r
404 if (Private->GopDevicePath == NULL) {\r
405 Status = EFI_OUT_OF_RESOURCES;\r
406 goto RestoreAttributes;\r
eaf4f336 407 }\r
d89186bc
LE
408\r
409 //\r
42d0cad7 410 // Create new child handle and install the device path protocol on it.\r
d89186bc 411 //\r
42d0cad7
LE
412 Status = gBS->InstallMultipleProtocolInterfaces (\r
413 &Private->Handle,\r
414 &gEfiDevicePathProtocolGuid,\r
415 Private->GopDevicePath,\r
416 NULL\r
417 );\r
418 if (EFI_ERROR (Status)) {\r
419 goto FreeGopDevicePath;\r
eaf4f336 420 }\r
421\r
422 //\r
423 // Construct video mode buffer\r
424 //\r
212aac55 425 switch (Private->Variant) {\r
426 case QEMU_VIDEO_CIRRUS_5430:\r
427 case QEMU_VIDEO_CIRRUS_5446:\r
428 Status = QemuVideoCirrusModeSetup (Private);\r
429 break;\r
cdb4f5dc 430 case QEMU_VIDEO_BOCHS_MMIO:\r
54f9b9ac 431 case QEMU_VIDEO_BOCHS:\r
b37bcfd6 432 Status = QemuVideoBochsModeSetup (Private, IsQxl);\r
54f9b9ac 433 break;\r
c137d950
PDJ
434 case QEMU_VIDEO_VMWARE_SVGA:\r
435 Status = QemuVideoVmwareSvgaModeSetup (Private);\r
436 break;\r
212aac55 437 default:\r
438 ASSERT (FALSE);\r
439 Status = EFI_DEVICE_ERROR;\r
440 break;\r
441 }\r
eaf4f336 442 if (EFI_ERROR (Status)) {\r
d89186bc 443 goto UninstallGopDevicePath;\r
eaf4f336 444 }\r
445\r
d89186bc
LE
446 //\r
447 // Start the GOP software stack.\r
448 //\r
449 Status = QemuVideoGraphicsOutputConstructor (Private);\r
450 if (EFI_ERROR (Status)) {\r
451 goto FreeModeData;\r
452 }\r
4374c2e5 453\r
d89186bc
LE
454 Status = gBS->InstallMultipleProtocolInterfaces (\r
455 &Private->Handle,\r
456 &gEfiGraphicsOutputProtocolGuid,\r
457 &Private->GraphicsOutput,\r
458 NULL\r
4374c2e5 459 );\r
d89186bc
LE
460 if (EFI_ERROR (Status)) {\r
461 goto DestructQemuVideoGraphics;\r
eaf4f336 462 }\r
463\r
d89186bc
LE
464 //\r
465 // Reference parent handle from child handle.\r
466 //\r
467 Status = gBS->OpenProtocol (\r
468 Controller,\r
469 &gEfiPciIoProtocolGuid,\r
470 (VOID **) &ChildPciIo,\r
471 This->DriverBindingHandle,\r
472 Private->Handle,\r
473 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
474 );\r
eaf4f336 475 if (EFI_ERROR (Status)) {\r
d89186bc
LE
476 goto UninstallGop;\r
477 }\r
eaf4f336 478\r
84a75f70 479#if defined MDE_CPU_IA32 || defined MDE_CPU_X64\r
90803342
LE
480 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||\r
481 Private->Variant == QEMU_VIDEO_BOCHS) {\r
482 InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase);\r
483 }\r
84a75f70 484#endif\r
90803342 485\r
9c08bbe5 486 gBS->RestoreTPL (OldTpl);\r
d89186bc
LE
487 return EFI_SUCCESS;\r
488\r
489UninstallGop:\r
490 gBS->UninstallProtocolInterface (Private->Handle,\r
491 &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput);\r
492\r
493DestructQemuVideoGraphics:\r
494 QemuVideoGraphicsOutputDestructor (Private);\r
495\r
496FreeModeData:\r
497 FreePool (Private->ModeData);\r
c137d950
PDJ
498 if (Private->VmwareSvgaModeInfo != NULL) {\r
499 FreePool (Private->VmwareSvgaModeInfo);\r
500 }\r
d89186bc
LE
501\r
502UninstallGopDevicePath:\r
d89186bc
LE
503 gBS->UninstallProtocolInterface (Private->Handle,\r
504 &gEfiDevicePathProtocolGuid, Private->GopDevicePath);\r
505\r
506FreeGopDevicePath:\r
42d0cad7 507 FreePool (Private->GopDevicePath);\r
eaf4f336 508\r
d89186bc
LE
509RestoreAttributes:\r
510 Private->PciIo->Attributes (Private->PciIo, EfiPciIoAttributeOperationSet,\r
511 Private->OriginalPciAttributes, NULL);\r
512\r
513ClosePciIo:\r
514 gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,\r
515 This->DriverBindingHandle, Controller);\r
516\r
517FreePrivate:\r
518 FreePool (Private);\r
519\r
9c08bbe5
LE
520RestoreTpl:\r
521 gBS->RestoreTPL (OldTpl);\r
522\r
eaf4f336 523 return Status;\r
524}\r
525\r
526/**\r
527 Stop this device\r
528\r
529 @param This The USB bus driver binding protocol.\r
530 @param Controller The controller to release.\r
531 @param NumberOfChildren The number of children of this device that\r
532 opened the controller BY_CHILD.\r
533 @param ChildHandleBuffer The array of child handle.\r
534\r
535 @retval EFI_SUCCESS The controller or children are stopped.\r
536 @retval EFI_DEVICE_ERROR Failed to stop the driver.\r
537\r
538**/\r
539EFI_STATUS\r
540EFIAPI\r
541QemuVideoControllerDriverStop (\r
542 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
543 IN EFI_HANDLE Controller,\r
544 IN UINTN NumberOfChildren,\r
545 IN EFI_HANDLE *ChildHandleBuffer\r
546 )\r
547{\r
548 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
549\r
550 EFI_STATUS Status;\r
551 QEMU_VIDEO_PRIVATE_DATA *Private;\r
552\r
99a6dce3
LE
553 if (NumberOfChildren == 0) {\r
554 //\r
555 // Close the PCI I/O Protocol\r
556 //\r
557 gBS->CloseProtocol (\r
558 Controller,\r
559 &gEfiPciIoProtocolGuid,\r
560 This->DriverBindingHandle,\r
561 Controller\r
562 );\r
563 return EFI_SUCCESS;\r
564 }\r
565\r
566 //\r
567 // free all resources for whose access we need the child handle, because the\r
568 // child handle is going away\r
569 //\r
570 ASSERT (NumberOfChildren == 1);\r
eaf4f336 571 Status = gBS->OpenProtocol (\r
99a6dce3 572 ChildHandleBuffer[0],\r
eaf4f336 573 &gEfiGraphicsOutputProtocolGuid,\r
574 (VOID **) &GraphicsOutput,\r
575 This->DriverBindingHandle,\r
576 Controller,\r
577 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
578 );\r
579 if (EFI_ERROR (Status)) {\r
580 return Status;\r
581 }\r
582\r
583 //\r
584 // Get our private context information\r
585 //\r
586 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);\r
99a6dce3 587 ASSERT (Private->Handle == ChildHandleBuffer[0]);\r
eaf4f336 588\r
589 QemuVideoGraphicsOutputDestructor (Private);\r
590 //\r
591 // Remove the GOP protocol interface from the system\r
592 //\r
593 Status = gBS->UninstallMultipleProtocolInterfaces (\r
594 Private->Handle,\r
595 &gEfiGraphicsOutputProtocolGuid,\r
596 &Private->GraphicsOutput,\r
597 NULL\r
598 );\r
599\r
600 if (EFI_ERROR (Status)) {\r
601 return Status;\r
602 }\r
603\r
604 //\r
605 // Restore original PCI attributes\r
606 //\r
607 Private->PciIo->Attributes (\r
608 Private->PciIo,\r
609 EfiPciIoAttributeOperationSet,\r
610 Private->OriginalPciAttributes,\r
611 NULL\r
612 );\r
613\r
4374c2e5
CR
614 gBS->CloseProtocol (\r
615 Controller,\r
616 &gEfiPciIoProtocolGuid,\r
617 This->DriverBindingHandle,\r
618 Private->Handle\r
619 );\r
620\r
847e4c34 621 FreePool (Private->ModeData);\r
c137d950
PDJ
622 if (Private->VmwareSvgaModeInfo != NULL) {\r
623 FreePool (Private->VmwareSvgaModeInfo);\r
624 }\r
847e4c34
LE
625 gBS->UninstallProtocolInterface (Private->Handle,\r
626 &gEfiDevicePathProtocolGuid, Private->GopDevicePath);\r
627 FreePool (Private->GopDevicePath);\r
628\r
eaf4f336 629 //\r
630 // Free our instance data\r
631 //\r
632 gBS->FreePool (Private);\r
633\r
634 return EFI_SUCCESS;\r
635}\r
636\r
637/**\r
638 TODO: Add function description\r
639\r
640 @param Private TODO: add argument description\r
641 @param Address TODO: add argument description\r
642 @param Data TODO: add argument description\r
643\r
644 TODO: add return values\r
645\r
646**/\r
647VOID\r
648outb (\r
649 QEMU_VIDEO_PRIVATE_DATA *Private,\r
650 UINTN Address,\r
651 UINT8 Data\r
652 )\r
653{\r
654 Private->PciIo->Io.Write (\r
655 Private->PciIo,\r
656 EfiPciIoWidthUint8,\r
657 EFI_PCI_IO_PASS_THROUGH_BAR,\r
658 Address,\r
659 1,\r
660 &Data\r
661 );\r
662}\r
663\r
664/**\r
665 TODO: Add function description\r
666\r
667 @param Private TODO: add argument description\r
668 @param Address TODO: add argument description\r
669 @param Data TODO: add argument description\r
670\r
671 TODO: add return values\r
672\r
673**/\r
674VOID\r
675outw (\r
676 QEMU_VIDEO_PRIVATE_DATA *Private,\r
677 UINTN Address,\r
678 UINT16 Data\r
679 )\r
680{\r
681 Private->PciIo->Io.Write (\r
682 Private->PciIo,\r
683 EfiPciIoWidthUint16,\r
684 EFI_PCI_IO_PASS_THROUGH_BAR,\r
685 Address,\r
686 1,\r
687 &Data\r
688 );\r
689}\r
690\r
691/**\r
692 TODO: Add function description\r
693\r
694 @param Private TODO: add argument description\r
695 @param Address TODO: add argument description\r
696\r
697 TODO: add return values\r
698\r
699**/\r
700UINT8\r
701inb (\r
702 QEMU_VIDEO_PRIVATE_DATA *Private,\r
703 UINTN Address\r
704 )\r
705{\r
706 UINT8 Data;\r
707\r
708 Private->PciIo->Io.Read (\r
709 Private->PciIo,\r
710 EfiPciIoWidthUint8,\r
711 EFI_PCI_IO_PASS_THROUGH_BAR,\r
712 Address,\r
713 1,\r
714 &Data\r
715 );\r
716 return Data;\r
717}\r
718\r
719/**\r
720 TODO: Add function description\r
721\r
722 @param Private TODO: add argument description\r
723 @param Address TODO: add argument description\r
724\r
725 TODO: add return values\r
726\r
727**/\r
728UINT16\r
729inw (\r
730 QEMU_VIDEO_PRIVATE_DATA *Private,\r
731 UINTN Address\r
732 )\r
733{\r
734 UINT16 Data;\r
735\r
736 Private->PciIo->Io.Read (\r
737 Private->PciIo,\r
738 EfiPciIoWidthUint16,\r
739 EFI_PCI_IO_PASS_THROUGH_BAR,\r
740 Address,\r
741 1,\r
742 &Data\r
743 );\r
744 return Data;\r
745}\r
746\r
747/**\r
748 TODO: Add function description\r
749\r
750 @param Private TODO: add argument description\r
751 @param Index TODO: add argument description\r
752 @param Red TODO: add argument description\r
753 @param Green TODO: add argument description\r
754 @param Blue TODO: add argument description\r
755\r
756 TODO: add return values\r
757\r
758**/\r
759VOID\r
760SetPaletteColor (\r
761 QEMU_VIDEO_PRIVATE_DATA *Private,\r
762 UINTN Index,\r
763 UINT8 Red,\r
764 UINT8 Green,\r
765 UINT8 Blue\r
766 )\r
767{\r
cdb4f5dc 768 VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);\r
769 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));\r
770 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));\r
771 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));\r
eaf4f336 772}\r
773\r
774/**\r
775 TODO: Add function description\r
776\r
777 @param Private TODO: add argument description\r
778\r
779 TODO: add return values\r
780\r
781**/\r
782VOID\r
783SetDefaultPalette (\r
784 QEMU_VIDEO_PRIVATE_DATA *Private\r
785 )\r
786{\r
787 UINTN Index;\r
788 UINTN RedIndex;\r
789 UINTN GreenIndex;\r
790 UINTN BlueIndex;\r
791\r
792 Index = 0;\r
793 for (RedIndex = 0; RedIndex < 8; RedIndex++) {\r
794 for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {\r
795 for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {\r
796 SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6));\r
797 Index++;\r
798 }\r
799 }\r
800 }\r
801}\r
802\r
803/**\r
804 TODO: Add function description\r
805\r
806 @param Private TODO: add argument description\r
807\r
808 TODO: add return values\r
809\r
810**/\r
811VOID\r
812ClearScreen (\r
813 QEMU_VIDEO_PRIVATE_DATA *Private\r
814 )\r
815{\r
816 UINT32 Color;\r
817\r
818 Color = 0;\r
819 Private->PciIo->Mem.Write (\r
820 Private->PciIo,\r
821 EfiPciIoWidthFillUint32,\r
c137d950 822 Private->FrameBufferVramBarIndex,\r
eaf4f336 823 0,\r
824 0x400000 >> 2,\r
825 &Color\r
826 );\r
827}\r
828\r
829/**\r
830 TODO: Add function description\r
831\r
832 @param Private TODO: add argument description\r
833\r
834 TODO: add return values\r
835\r
836**/\r
837VOID\r
838DrawLogo (\r
839 QEMU_VIDEO_PRIVATE_DATA *Private,\r
840 UINTN ScreenWidth,\r
841 UINTN ScreenHeight\r
842 )\r
843{\r
844}\r
845\r
846/**\r
847 TODO: Add function description\r
848\r
849 @param Private TODO: add argument description\r
850 @param ModeData TODO: add argument description\r
851\r
852 TODO: add return values\r
853\r
854**/\r
855VOID\r
212aac55 856InitializeCirrusGraphicsMode (\r
eaf4f336 857 QEMU_VIDEO_PRIVATE_DATA *Private,\r
212aac55 858 QEMU_VIDEO_CIRRUS_MODES *ModeData\r
eaf4f336 859 )\r
860{\r
861 UINT8 Byte;\r
862 UINTN Index;\r
eaf4f336 863\r
864 outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);\r
865 outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);\r
866\r
867 for (Index = 0; Index < 15; Index++) {\r
868 outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);\r
869 }\r
870\r
212aac55 871 if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {\r
eaf4f336 872 outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);\r
873 Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);\r
874 outb (Private, SEQ_DATA_REGISTER, Byte);\r
875 }\r
876\r
877 outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);\r
878 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);\r
879 outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);\r
880 outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);\r
881\r
882 for (Index = 0; Index < 28; Index++) {\r
883 outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index));\r
884 }\r
885\r
886 for (Index = 0; Index < 9; Index++) {\r
887 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index));\r
888 }\r
889\r
890 inb (Private, INPUT_STATUS_1_REGISTER);\r
891\r
892 for (Index = 0; Index < 21; Index++) {\r
893 outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index);\r
894 outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);\r
895 }\r
896\r
897 outb (Private, ATT_ADDRESS_REGISTER, 0x20);\r
898\r
899 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);\r
900 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);\r
901 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);\r
902 outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);\r
903\r
54f9b9ac 904 SetDefaultPalette (Private);\r
905 ClearScreen (Private);\r
906}\r
907\r
908VOID\r
909BochsWrite (\r
910 QEMU_VIDEO_PRIVATE_DATA *Private,\r
911 UINT16 Reg,\r
912 UINT16 Data\r
913 )\r
914{\r
cdb4f5dc 915 EFI_STATUS Status;\r
916\r
917 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
918 Status = Private->PciIo->Mem.Write (\r
919 Private->PciIo,\r
920 EfiPciIoWidthUint16,\r
921 PCI_BAR_IDX2,\r
922 0x500 + (Reg << 1),\r
923 1,\r
924 &Data\r
925 );\r
926 ASSERT_EFI_ERROR (Status);\r
927 } else {\r
928 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);\r
929 outw (Private, VBE_DISPI_IOPORT_DATA, Data);\r
930 }\r
54f9b9ac 931}\r
932\r
933UINT16\r
934BochsRead (\r
935 QEMU_VIDEO_PRIVATE_DATA *Private,\r
936 UINT16 Reg\r
937 )\r
938{\r
cdb4f5dc 939 EFI_STATUS Status;\r
940 UINT16 Data;\r
941\r
942 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
943 Status = Private->PciIo->Mem.Read (\r
944 Private->PciIo,\r
945 EfiPciIoWidthUint16,\r
946 PCI_BAR_IDX2,\r
947 0x500 + (Reg << 1),\r
948 1,\r
949 &Data\r
950 );\r
951 ASSERT_EFI_ERROR (Status);\r
952 } else {\r
953 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);\r
954 Data = inw (Private, VBE_DISPI_IOPORT_DATA);\r
955 }\r
54f9b9ac 956 return Data;\r
957}\r
958\r
c137d950
PDJ
959VOID\r
960VmwareSvgaWrite (\r
961 QEMU_VIDEO_PRIVATE_DATA *Private,\r
962 UINT16 Register,\r
963 UINT32 Value\r
964 )\r
965{\r
966 UnalignedIoWrite32 (\r
967 Private->VmwareSvgaBasePort + VMWARE_SVGA_INDEX_PORT,\r
968 Register\r
969 );\r
970 UnalignedIoWrite32 (\r
971 Private->VmwareSvgaBasePort + VMWARE_SVGA_VALUE_PORT,\r
972 Value\r
973 );\r
974}\r
975\r
976UINT32\r
977VmwareSvgaRead (\r
978 QEMU_VIDEO_PRIVATE_DATA *Private,\r
979 UINT16 Register\r
980 )\r
981{\r
982 UnalignedIoWrite32 (\r
983 Private->VmwareSvgaBasePort + VMWARE_SVGA_INDEX_PORT,\r
984 Register\r
985 );\r
986 return UnalignedIoRead32 (\r
987 Private->VmwareSvgaBasePort + VMWARE_SVGA_VALUE_PORT\r
988 );\r
989}\r
990\r
cdb4f5dc 991VOID\r
992VgaOutb (\r
993 QEMU_VIDEO_PRIVATE_DATA *Private,\r
994 UINTN Reg,\r
995 UINT8 Data\r
996 )\r
997{\r
998 EFI_STATUS Status;\r
999\r
1000 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
1001 Status = Private->PciIo->Mem.Write (\r
1002 Private->PciIo,\r
1003 EfiPciIoWidthUint8,\r
1004 PCI_BAR_IDX2,\r
1005 0x400 - 0x3c0 + Reg,\r
1006 1,\r
1007 &Data\r
1008 );\r
1009 ASSERT_EFI_ERROR (Status);\r
1010 } else {\r
1011 outb (Private, Reg, Data);\r
1012 }\r
1013}\r
1014\r
54f9b9ac 1015VOID\r
1016InitializeBochsGraphicsMode (\r
1017 QEMU_VIDEO_PRIVATE_DATA *Private,\r
1018 QEMU_VIDEO_BOCHS_MODES *ModeData\r
1019 )\r
1020{\r
1021 DEBUG ((EFI_D_INFO, "InitializeBochsGraphicsMode: %dx%d @ %d\n",\r
1022 ModeData->Width, ModeData->Height, ModeData->ColorDepth));\r
1023\r
1024 /* unblank */\r
cdb4f5dc 1025 VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);\r
54f9b9ac 1026\r
1027 BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, 0);\r
1028 BochsWrite (Private, VBE_DISPI_INDEX_BANK, 0);\r
1029 BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET, 0);\r
1030 BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET, 0);\r
1031\r
1032 BochsWrite (Private, VBE_DISPI_INDEX_BPP, (UINT16) ModeData->ColorDepth);\r
1033 BochsWrite (Private, VBE_DISPI_INDEX_XRES, (UINT16) ModeData->Width);\r
1034 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH, (UINT16) ModeData->Width);\r
1035 BochsWrite (Private, VBE_DISPI_INDEX_YRES, (UINT16) ModeData->Height);\r
1036 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16) ModeData->Height);\r
1037\r
1038 BochsWrite (Private, VBE_DISPI_INDEX_ENABLE,\r
1039 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);\r
1040\r
c137d950
PDJ
1041 SetDefaultPalette (Private);\r
1042 ClearScreen (Private);\r
1043}\r
1044\r
1045VOID\r
1046InitializeVmwareSvgaGraphicsMode (\r
1047 QEMU_VIDEO_PRIVATE_DATA *Private,\r
1048 QEMU_VIDEO_BOCHS_MODES *ModeData\r
1049 )\r
1050{\r
1051 UINT32 Capabilities;\r
1052\r
1053 VmwareSvgaWrite (Private, VmwareSvgaRegWidth, ModeData->Width);\r
1054 VmwareSvgaWrite (Private, VmwareSvgaRegHeight, ModeData->Height);\r
1055\r
1056 Capabilities = VmwareSvgaRead (\r
1057 Private,\r
1058 VmwareSvgaRegCapabilities\r
1059 );\r
1060 if ((Capabilities & VMWARE_SVGA_CAP_8BIT_EMULATION) != 0) {\r
1061 VmwareSvgaWrite (\r
1062 Private,\r
1063 VmwareSvgaRegBitsPerPixel,\r
1064 ModeData->ColorDepth\r
1065 );\r
1066 }\r
1067\r
1068 VmwareSvgaWrite (Private, VmwareSvgaRegEnable, 1);\r
1069\r
eaf4f336 1070 SetDefaultPalette (Private);\r
1071 ClearScreen (Private);\r
1072}\r
1073\r
1074EFI_STATUS\r
1075EFIAPI\r
1076InitializeQemuVideo (\r
1077 IN EFI_HANDLE ImageHandle,\r
1078 IN EFI_SYSTEM_TABLE *SystemTable\r
1079 )\r
1080{\r
1081 EFI_STATUS Status;\r
1082\r
1083 Status = EfiLibInstallDriverBindingComponentName2 (\r
1084 ImageHandle,\r
1085 SystemTable,\r
1086 &gQemuVideoDriverBinding,\r
1087 ImageHandle,\r
1088 &gQemuVideoComponentName,\r
1089 &gQemuVideoComponentName2\r
1090 );\r
1091 ASSERT_EFI_ERROR (Status);\r
1092\r
1093 //\r
1094 // Install EFI Driver Supported EFI Version Protocol required for\r
1095 // EFI drivers that are on PCI and other plug in cards.\r
1096 //\r
1097 gQemuVideoDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);\r
1098 Status = gBS->InstallMultipleProtocolInterfaces (\r
1099 &ImageHandle,\r
1100 &gEfiDriverSupportedEfiVersionProtocolGuid,\r
1101 &gQemuVideoDriverSupportedEfiVersion,\r
1102 NULL\r
1103 );\r
1104 ASSERT_EFI_ERROR (Status);\r
1105\r
1106 return Status;\r
1107}\r