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