2 This driver is a sample implementation of the Graphics Output Protocol for
3 the QEMU (Cirrus Logic 5446) video controller.
5 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding
= {
20 QemuVideoControllerDriverSupported
,
21 QemuVideoControllerDriverStart
,
22 QemuVideoControllerDriverStop
,
28 QEMU_VIDEO_CARD gQemuVideoCardList
[] = {
30 CIRRUS_LOGIC_VENDOR_ID
,
31 CIRRUS_LOGIC_5430_DEVICE_ID
,
32 QEMU_VIDEO_CIRRUS_5430
,
35 CIRRUS_LOGIC_VENDOR_ID
,
36 CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID
,
37 QEMU_VIDEO_CIRRUS_5430
,
40 CIRRUS_LOGIC_VENDOR_ID
,
41 CIRRUS_LOGIC_5446_DEVICE_ID
,
42 QEMU_VIDEO_CIRRUS_5446
,
59 static QEMU_VIDEO_CARD
*
67 while (gQemuVideoCardList
[Index
].VendorId
!= 0) {
68 if (gQemuVideoCardList
[Index
].VendorId
== VendorId
&&
69 gQemuVideoCardList
[Index
].DeviceId
== DeviceId
) {
70 return gQemuVideoCardList
+ Index
;
78 Check if this device is supported.
80 @param This The driver binding protocol.
81 @param Controller The controller handle to check.
82 @param RemainingDevicePath The remaining device path.
84 @retval EFI_SUCCESS The bus supports this controller.
85 @retval EFI_UNSUPPORTED This device isn't supported.
90 QemuVideoControllerDriverSupported (
91 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
92 IN EFI_HANDLE Controller
,
93 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
97 EFI_PCI_IO_PROTOCOL
*PciIo
;
100 QEMU_VIDEO_CARD
*Card
;
103 // Open the PCI I/O Protocol
105 Status
= gBS
->OpenProtocol (
107 &gEfiPciIoProtocolGuid
,
109 This
->DriverBindingHandle
,
111 EFI_OPEN_PROTOCOL_BY_DRIVER
113 if (EFI_ERROR (Status
)) {
118 // Read the PCI Configuration Header from the PCI Device
120 Status
= PciIo
->Pci
.Read (
124 sizeof (Pci
) / sizeof (UINT32
),
127 if (EFI_ERROR (Status
)) {
131 Status
= EFI_UNSUPPORTED
;
133 // See if the I/O enable is on. Most systems only allow one VGA device to be turned on
134 // at a time, so see if this is one that is turned on.
136 // if (((Pci.Hdr.Command & 0x01) == 0x01)) {
138 // See if this is a Cirrus Logic PCI controller
140 Card
= QemuVideoDetect(Pci
.Hdr
.VendorId
, Pci
.Hdr
.DeviceId
);
142 DEBUG ((EFI_D_INFO
, "QemuVideo: %s detected\n", Card
->Name
));
143 Status
= EFI_SUCCESS
;
145 // If this is an Intel 945 graphics controller,
146 // go further check RemainingDevicePath validation
148 if (RemainingDevicePath
!= NULL
) {
149 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
151 // Check if RemainingDevicePath is the End of Device Path Node,
152 // if yes, return EFI_SUCCESS
154 if (!IsDevicePathEnd (Node
)) {
156 // If RemainingDevicePath isn't the End of Device Path Node,
157 // check its validation
159 if (Node
->DevPath
.Type
!= ACPI_DEVICE_PATH
||
160 Node
->DevPath
.SubType
!= ACPI_ADR_DP
||
161 DevicePathNodeLength(&Node
->DevPath
) != sizeof(ACPI_ADR_DEVICE_PATH
)) {
162 Status
= EFI_UNSUPPORTED
;
170 // Close the PCI I/O Protocol
174 &gEfiPciIoProtocolGuid
,
175 This
->DriverBindingHandle
,
183 Start to process the controller.
185 @param This The USB bus driver binding instance.
186 @param Controller The controller to check.
187 @param RemainingDevicePath The remaining device patch.
189 @retval EFI_SUCCESS The controller is controlled by the usb bus.
190 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
192 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
197 QemuVideoControllerDriverStart (
198 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
199 IN EFI_HANDLE Controller
,
200 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
204 QEMU_VIDEO_PRIVATE_DATA
*Private
;
205 BOOLEAN PciAttributesSaved
;
206 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
207 ACPI_ADR_DEVICE_PATH AcpiDeviceNode
;
209 QEMU_VIDEO_CARD
*Card
;
211 PciAttributesSaved
= FALSE
;
213 // Allocate Private context data for GOP inteface.
215 Private
= AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA
));
216 if (Private
== NULL
) {
217 Status
= EFI_OUT_OF_RESOURCES
;
222 // Set up context record
224 Private
->Signature
= QEMU_VIDEO_PRIVATE_DATA_SIGNATURE
;
225 Private
->Handle
= NULL
;
228 // Open PCI I/O Protocol
230 Status
= gBS
->OpenProtocol (
232 &gEfiPciIoProtocolGuid
,
233 (VOID
**) &Private
->PciIo
,
234 This
->DriverBindingHandle
,
236 EFI_OPEN_PROTOCOL_BY_DRIVER
238 if (EFI_ERROR (Status
)) {
243 // Read the PCI Configuration Header from the PCI Device
245 Status
= Private
->PciIo
->Pci
.Read (
249 sizeof (Pci
) / sizeof (UINT32
),
252 if (EFI_ERROR (Status
)) {
256 Card
= QemuVideoDetect(Pci
.Hdr
.VendorId
, Pci
.Hdr
.DeviceId
);
258 Status
= EFI_DEVICE_ERROR
;
261 Private
->Variant
= Card
->Variant
;
264 // Save original PCI attributes
266 Status
= Private
->PciIo
->Attributes (
268 EfiPciIoAttributeOperationGet
,
270 &Private
->OriginalPciAttributes
273 if (EFI_ERROR (Status
)) {
276 PciAttributesSaved
= TRUE
;
278 Status
= Private
->PciIo
->Attributes (
280 EfiPciIoAttributeOperationEnable
,
281 EFI_PCI_DEVICE_ENABLE
| EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
| EFI_PCI_IO_ATTRIBUTE_VGA_IO
,
284 if (EFI_ERROR (Status
)) {
289 // Check if accessing the bochs interface works.
291 if (Private
->Variant
== QEMU_VIDEO_BOCHS
) {
293 BochsId
= BochsRead(Private
, VBE_DISPI_INDEX_ID
);
294 if ((BochsId
& 0xFFF0) != VBE_DISPI_ID0
) {
295 DEBUG ((EFI_D_INFO
, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId
));
296 Status
= EFI_DEVICE_ERROR
;
302 // Get ParentDevicePath
304 Status
= gBS
->HandleProtocol (
306 &gEfiDevicePathProtocolGuid
,
307 (VOID
**) &ParentDevicePath
309 if (EFI_ERROR (Status
)) {
314 // Set Gop Device Path
316 if (RemainingDevicePath
== NULL
) {
317 ZeroMem (&AcpiDeviceNode
, sizeof (ACPI_ADR_DEVICE_PATH
));
318 AcpiDeviceNode
.Header
.Type
= ACPI_DEVICE_PATH
;
319 AcpiDeviceNode
.Header
.SubType
= ACPI_ADR_DP
;
320 AcpiDeviceNode
.ADR
= ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA
, 0, 0);
321 SetDevicePathNodeLength (&AcpiDeviceNode
.Header
, sizeof (ACPI_ADR_DEVICE_PATH
));
323 Private
->GopDevicePath
= AppendDevicePathNode (
325 (EFI_DEVICE_PATH_PROTOCOL
*) &AcpiDeviceNode
327 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
329 // If RemainingDevicePath isn't the End of Device Path Node,
330 // only scan the specified device by RemainingDevicePath
332 Private
->GopDevicePath
= AppendDevicePathNode (ParentDevicePath
, RemainingDevicePath
);
335 // If RemainingDevicePath is the End of Device Path Node,
336 // don't create child device and return EFI_SUCCESS
338 Private
->GopDevicePath
= NULL
;
341 if (Private
->GopDevicePath
!= NULL
) {
343 // Creat child handle and device path protocol firstly
345 Private
->Handle
= NULL
;
346 Status
= gBS
->InstallMultipleProtocolInterfaces (
348 &gEfiDevicePathProtocolGuid
,
349 Private
->GopDevicePath
,
355 // Construct video mode buffer
357 switch (Private
->Variant
) {
358 case QEMU_VIDEO_CIRRUS_5430
:
359 case QEMU_VIDEO_CIRRUS_5446
:
360 Status
= QemuVideoCirrusModeSetup (Private
);
362 case QEMU_VIDEO_BOCHS
:
363 Status
= QemuVideoBochsModeSetup (Private
);
367 Status
= EFI_DEVICE_ERROR
;
370 if (EFI_ERROR (Status
)) {
374 if (Private
->GopDevicePath
== NULL
) {
376 // If RemainingDevicePath is the End of Device Path Node,
377 // don't create child device and return EFI_SUCCESS
379 Status
= EFI_SUCCESS
;
383 // Start the GOP software stack.
385 Status
= QemuVideoGraphicsOutputConstructor (Private
);
386 ASSERT_EFI_ERROR (Status
);
388 Status
= gBS
->InstallMultipleProtocolInterfaces (
390 &gEfiGraphicsOutputProtocolGuid
,
391 &Private
->GraphicsOutput
,
397 if (EFI_ERROR (Status
)) {
399 if (Private
->PciIo
) {
400 if (PciAttributesSaved
== TRUE
) {
402 // Restore original PCI attributes
404 Private
->PciIo
->Attributes (
406 EfiPciIoAttributeOperationSet
,
407 Private
->OriginalPciAttributes
,
412 // Close the PCI I/O Protocol
416 &gEfiPciIoProtocolGuid
,
417 This
->DriverBindingHandle
,
422 gBS
->FreePool (Private
);
432 @param This The USB bus driver binding protocol.
433 @param Controller The controller to release.
434 @param NumberOfChildren The number of children of this device that
435 opened the controller BY_CHILD.
436 @param ChildHandleBuffer The array of child handle.
438 @retval EFI_SUCCESS The controller or children are stopped.
439 @retval EFI_DEVICE_ERROR Failed to stop the driver.
444 QemuVideoControllerDriverStop (
445 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
446 IN EFI_HANDLE Controller
,
447 IN UINTN NumberOfChildren
,
448 IN EFI_HANDLE
*ChildHandleBuffer
451 EFI_GRAPHICS_OUTPUT_PROTOCOL
*GraphicsOutput
;
454 QEMU_VIDEO_PRIVATE_DATA
*Private
;
456 Status
= gBS
->OpenProtocol (
458 &gEfiGraphicsOutputProtocolGuid
,
459 (VOID
**) &GraphicsOutput
,
460 This
->DriverBindingHandle
,
462 EFI_OPEN_PROTOCOL_GET_PROTOCOL
464 if (EFI_ERROR (Status
)) {
469 // Get our private context information
471 Private
= QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput
);
473 QemuVideoGraphicsOutputDestructor (Private
);
475 // Remove the GOP protocol interface from the system
477 Status
= gBS
->UninstallMultipleProtocolInterfaces (
479 &gEfiGraphicsOutputProtocolGuid
,
480 &Private
->GraphicsOutput
,
484 if (EFI_ERROR (Status
)) {
489 // Restore original PCI attributes
491 Private
->PciIo
->Attributes (
493 EfiPciIoAttributeOperationSet
,
494 Private
->OriginalPciAttributes
,
499 // Close the PCI I/O Protocol
503 &gEfiPciIoProtocolGuid
,
504 This
->DriverBindingHandle
,
509 // Free our instance data
511 gBS
->FreePool (Private
);
517 TODO: Add function description
519 @param Private TODO: add argument description
520 @param Address TODO: add argument description
521 @param Data TODO: add argument description
523 TODO: add return values
528 QEMU_VIDEO_PRIVATE_DATA
*Private
,
533 Private
->PciIo
->Io
.Write (
536 EFI_PCI_IO_PASS_THROUGH_BAR
,
544 TODO: Add function description
546 @param Private TODO: add argument description
547 @param Address TODO: add argument description
548 @param Data TODO: add argument description
550 TODO: add return values
555 QEMU_VIDEO_PRIVATE_DATA
*Private
,
560 Private
->PciIo
->Io
.Write (
563 EFI_PCI_IO_PASS_THROUGH_BAR
,
571 TODO: Add function description
573 @param Private TODO: add argument description
574 @param Address TODO: add argument description
576 TODO: add return values
581 QEMU_VIDEO_PRIVATE_DATA
*Private
,
587 Private
->PciIo
->Io
.Read (
590 EFI_PCI_IO_PASS_THROUGH_BAR
,
599 TODO: Add function description
601 @param Private TODO: add argument description
602 @param Address TODO: add argument description
604 TODO: add return values
609 QEMU_VIDEO_PRIVATE_DATA
*Private
,
615 Private
->PciIo
->Io
.Read (
618 EFI_PCI_IO_PASS_THROUGH_BAR
,
627 TODO: Add function description
629 @param Private TODO: add argument description
630 @param Index TODO: add argument description
631 @param Red TODO: add argument description
632 @param Green TODO: add argument description
633 @param Blue TODO: add argument description
635 TODO: add return values
640 QEMU_VIDEO_PRIVATE_DATA
*Private
,
647 outb (Private
, PALETTE_INDEX_REGISTER
, (UINT8
) Index
);
648 outb (Private
, PALETTE_DATA_REGISTER
, (UINT8
) (Red
>> 2));
649 outb (Private
, PALETTE_DATA_REGISTER
, (UINT8
) (Green
>> 2));
650 outb (Private
, PALETTE_DATA_REGISTER
, (UINT8
) (Blue
>> 2));
654 TODO: Add function description
656 @param Private TODO: add argument description
658 TODO: add return values
663 QEMU_VIDEO_PRIVATE_DATA
*Private
672 for (RedIndex
= 0; RedIndex
< 8; RedIndex
++) {
673 for (GreenIndex
= 0; GreenIndex
< 8; GreenIndex
++) {
674 for (BlueIndex
= 0; BlueIndex
< 4; BlueIndex
++) {
675 SetPaletteColor (Private
, Index
, (UINT8
) (RedIndex
<< 5), (UINT8
) (GreenIndex
<< 5), (UINT8
) (BlueIndex
<< 6));
683 TODO: Add function description
685 @param Private TODO: add argument description
687 TODO: add return values
692 QEMU_VIDEO_PRIVATE_DATA
*Private
698 Private
->PciIo
->Mem
.Write (
700 EfiPciIoWidthFillUint32
,
709 TODO: Add function description
711 @param Private TODO: add argument description
713 TODO: add return values
718 QEMU_VIDEO_PRIVATE_DATA
*Private
,
726 TODO: Add function description
728 @param Private TODO: add argument description
729 @param ModeData TODO: add argument description
731 TODO: add return values
735 InitializeCirrusGraphicsMode (
736 QEMU_VIDEO_PRIVATE_DATA
*Private
,
737 QEMU_VIDEO_CIRRUS_MODES
*ModeData
743 outw (Private
, SEQ_ADDRESS_REGISTER
, 0x1206);
744 outw (Private
, SEQ_ADDRESS_REGISTER
, 0x0012);
746 for (Index
= 0; Index
< 15; Index
++) {
747 outw (Private
, SEQ_ADDRESS_REGISTER
, ModeData
->SeqSettings
[Index
]);
750 if (Private
->Variant
== QEMU_VIDEO_CIRRUS_5430
) {
751 outb (Private
, SEQ_ADDRESS_REGISTER
, 0x0f);
752 Byte
= (UINT8
) ((inb (Private
, SEQ_DATA_REGISTER
) & 0xc7) ^ 0x30);
753 outb (Private
, SEQ_DATA_REGISTER
, Byte
);
756 outb (Private
, MISC_OUTPUT_REGISTER
, ModeData
->MiscSetting
);
757 outw (Private
, GRAPH_ADDRESS_REGISTER
, 0x0506);
758 outw (Private
, SEQ_ADDRESS_REGISTER
, 0x0300);
759 outw (Private
, CRTC_ADDRESS_REGISTER
, 0x2011);
761 for (Index
= 0; Index
< 28; Index
++) {
762 outw (Private
, CRTC_ADDRESS_REGISTER
, (UINT16
) ((ModeData
->CrtcSettings
[Index
] << 8) | Index
));
765 for (Index
= 0; Index
< 9; Index
++) {
766 outw (Private
, GRAPH_ADDRESS_REGISTER
, (UINT16
) ((GraphicsController
[Index
] << 8) | Index
));
769 inb (Private
, INPUT_STATUS_1_REGISTER
);
771 for (Index
= 0; Index
< 21; Index
++) {
772 outb (Private
, ATT_ADDRESS_REGISTER
, (UINT8
) Index
);
773 outb (Private
, ATT_ADDRESS_REGISTER
, AttributeController
[Index
]);
776 outb (Private
, ATT_ADDRESS_REGISTER
, 0x20);
778 outw (Private
, GRAPH_ADDRESS_REGISTER
, 0x0009);
779 outw (Private
, GRAPH_ADDRESS_REGISTER
, 0x000a);
780 outw (Private
, GRAPH_ADDRESS_REGISTER
, 0x000b);
781 outb (Private
, DAC_PIXEL_MASK_REGISTER
, 0xff);
783 SetDefaultPalette (Private
);
784 ClearScreen (Private
);
789 QEMU_VIDEO_PRIVATE_DATA
*Private
,
794 outw (Private
, VBE_DISPI_IOPORT_INDEX
, Reg
);
795 outw (Private
, VBE_DISPI_IOPORT_DATA
, Data
);
800 QEMU_VIDEO_PRIVATE_DATA
*Private
,
806 outw (Private
, VBE_DISPI_IOPORT_INDEX
, Reg
);
807 Data
= inw (Private
, VBE_DISPI_IOPORT_DATA
);
812 InitializeBochsGraphicsMode (
813 QEMU_VIDEO_PRIVATE_DATA
*Private
,
814 QEMU_VIDEO_BOCHS_MODES
*ModeData
817 DEBUG ((EFI_D_INFO
, "InitializeBochsGraphicsMode: %dx%d @ %d\n",
818 ModeData
->Width
, ModeData
->Height
, ModeData
->ColorDepth
));
821 outb (Private
, ATT_ADDRESS_REGISTER
, 0x20);
823 BochsWrite (Private
, VBE_DISPI_INDEX_ENABLE
, 0);
824 BochsWrite (Private
, VBE_DISPI_INDEX_BANK
, 0);
825 BochsWrite (Private
, VBE_DISPI_INDEX_X_OFFSET
, 0);
826 BochsWrite (Private
, VBE_DISPI_INDEX_Y_OFFSET
, 0);
828 BochsWrite (Private
, VBE_DISPI_INDEX_BPP
, (UINT16
) ModeData
->ColorDepth
);
829 BochsWrite (Private
, VBE_DISPI_INDEX_XRES
, (UINT16
) ModeData
->Width
);
830 BochsWrite (Private
, VBE_DISPI_INDEX_VIRT_WIDTH
, (UINT16
) ModeData
->Width
);
831 BochsWrite (Private
, VBE_DISPI_INDEX_YRES
, (UINT16
) ModeData
->Height
);
832 BochsWrite (Private
, VBE_DISPI_INDEX_VIRT_HEIGHT
, (UINT16
) ModeData
->Height
);
834 BochsWrite (Private
, VBE_DISPI_INDEX_ENABLE
,
835 VBE_DISPI_ENABLED
| VBE_DISPI_LFB_ENABLED
);
837 SetDefaultPalette (Private
);
838 ClearScreen (Private
);
843 InitializeQemuVideo (
844 IN EFI_HANDLE ImageHandle
,
845 IN EFI_SYSTEM_TABLE
*SystemTable
850 Status
= EfiLibInstallDriverBindingComponentName2 (
853 &gQemuVideoDriverBinding
,
855 &gQemuVideoComponentName
,
856 &gQemuVideoComponentName2
858 ASSERT_EFI_ERROR (Status
);
861 // Install EFI Driver Supported EFI Version Protocol required for
862 // EFI drivers that are on PCI and other plug in cards.
864 gQemuVideoDriverSupportedEfiVersion
.FirmwareVersion
= PcdGet32 (PcdDriverSupportedEfiVersion
);
865 Status
= gBS
->InstallMultipleProtocolInterfaces (
867 &gEfiDriverSupportedEfiVersionProtocolGuid
,
868 &gQemuVideoDriverSupportedEfiVersion
,
871 ASSERT_EFI_ERROR (Status
);