| /** @file | |
| This driver is a sample implementation of the Graphics Output Protocol for | |
| the QEMU (Cirrus Logic 5446) video controller. | |
| Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "Qemu.h" | |
| #include <IndustryStandard/Acpi.h> | |
| EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = { | |
| QemuVideoControllerDriverSupported, | |
| QemuVideoControllerDriverStart, | |
| QemuVideoControllerDriverStop, | |
| 0x10, | |
| NULL, | |
| NULL | |
| }; | |
| QEMU_VIDEO_CARD gQemuVideoCardList[] = { | |
| { | |
| PCI_CLASS_DISPLAY_VGA, | |
| CIRRUS_LOGIC_VENDOR_ID, | |
| CIRRUS_LOGIC_5430_DEVICE_ID, | |
| QEMU_VIDEO_CIRRUS_5430, | |
| L"Cirrus 5430" | |
| },{ | |
| PCI_CLASS_DISPLAY_VGA, | |
| CIRRUS_LOGIC_VENDOR_ID, | |
| CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID, | |
| QEMU_VIDEO_CIRRUS_5430, | |
| L"Cirrus 5430" | |
| },{ | |
| PCI_CLASS_DISPLAY_VGA, | |
| CIRRUS_LOGIC_VENDOR_ID, | |
| CIRRUS_LOGIC_5446_DEVICE_ID, | |
| QEMU_VIDEO_CIRRUS_5446, | |
| L"Cirrus 5446" | |
| },{ | |
| PCI_CLASS_DISPLAY_VGA, | |
| 0x1234, | |
| 0x1111, | |
| QEMU_VIDEO_BOCHS_MMIO, | |
| L"QEMU Standard VGA" | |
| },{ | |
| PCI_CLASS_DISPLAY_OTHER, | |
| 0x1234, | |
| 0x1111, | |
| QEMU_VIDEO_BOCHS_MMIO, | |
| L"QEMU Standard VGA (secondary)" | |
| },{ | |
| PCI_CLASS_DISPLAY_VGA, | |
| 0x1b36, | |
| 0x0100, | |
| QEMU_VIDEO_BOCHS, | |
| L"QEMU QXL VGA" | |
| },{ | |
| PCI_CLASS_DISPLAY_VGA, | |
| 0x1af4, | |
| 0x1050, | |
| QEMU_VIDEO_BOCHS_MMIO, | |
| L"QEMU VirtIO VGA" | |
| },{ | |
| PCI_CLASS_DISPLAY_VGA, | |
| 0x15ad, | |
| 0x0405, | |
| QEMU_VIDEO_VMWARE_SVGA, | |
| L"QEMU VMWare SVGA" | |
| },{ | |
| 0 /* end of list */ | |
| } | |
| }; | |
| static QEMU_VIDEO_CARD * | |
| QemuVideoDetect ( | |
| IN UINT8 SubClass, | |
| IN UINT16 VendorId, | |
| IN UINT16 DeviceId | |
| ) | |
| { | |
| UINTN Index = 0; | |
| while (gQemuVideoCardList[Index].VendorId != 0) { | |
| if ((gQemuVideoCardList[Index].SubClass == SubClass) && | |
| (gQemuVideoCardList[Index].VendorId == VendorId) && | |
| (gQemuVideoCardList[Index].DeviceId == DeviceId)) | |
| { | |
| return gQemuVideoCardList + Index; | |
| } | |
| Index++; | |
| } | |
| return NULL; | |
| } | |
| /** | |
| Check if this device is supported. | |
| @param This The driver binding protocol. | |
| @param Controller The controller handle to check. | |
| @param RemainingDevicePath The remaining device path. | |
| @retval EFI_SUCCESS The bus supports this controller. | |
| @retval EFI_UNSUPPORTED This device isn't supported. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| QemuVideoControllerDriverSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| PCI_TYPE00 Pci; | |
| QEMU_VIDEO_CARD *Card; | |
| // | |
| // Open the PCI I/O Protocol | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| (VOID **)&PciIo, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Read the PCI Configuration Header from the PCI Device | |
| // | |
| Status = PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| 0, | |
| sizeof (Pci) / sizeof (UINT32), | |
| &Pci | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| Status = EFI_UNSUPPORTED; | |
| if (!IS_PCI_DISPLAY (&Pci)) { | |
| goto Done; | |
| } | |
| Card = QemuVideoDetect (Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId); | |
| if (Card != NULL) { | |
| DEBUG ((DEBUG_INFO, "QemuVideo: %s detected\n", Card->Name)); | |
| Status = EFI_SUCCESS; | |
| } | |
| Done: | |
| // | |
| // Close the PCI I/O Protocol | |
| // | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Start to process the controller. | |
| @param This The USB bus driver binding instance. | |
| @param Controller The controller to check. | |
| @param RemainingDevicePath The remaining device patch. | |
| @retval EFI_SUCCESS The controller is controlled by the usb bus. | |
| @retval EFI_ALREADY_STARTED The controller is already controlled by the usb | |
| bus. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| QemuVideoControllerDriverStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_TPL OldTpl; | |
| EFI_STATUS Status; | |
| QEMU_VIDEO_PRIVATE_DATA *Private; | |
| BOOLEAN IsQxl; | |
| EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; | |
| ACPI_ADR_DEVICE_PATH AcpiDeviceNode; | |
| PCI_TYPE00 Pci; | |
| QEMU_VIDEO_CARD *Card; | |
| EFI_PCI_IO_PROTOCOL *ChildPciIo; | |
| UINT64 SupportedVgaIo; | |
| OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
| // | |
| // Allocate Private context data for GOP interface. | |
| // | |
| Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA)); | |
| if (Private == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto RestoreTpl; | |
| } | |
| // | |
| // Set up context record | |
| // | |
| Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE; | |
| // | |
| // Open PCI I/O Protocol | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| (VOID **)&Private->PciIo, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto FreePrivate; | |
| } | |
| // | |
| // Read the PCI Configuration Header from the PCI Device | |
| // | |
| Status = Private->PciIo->Pci.Read ( | |
| Private->PciIo, | |
| EfiPciIoWidthUint32, | |
| 0, | |
| sizeof (Pci) / sizeof (UINT32), | |
| &Pci | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ClosePciIo; | |
| } | |
| // | |
| // Determine card variant. | |
| // | |
| Card = QemuVideoDetect (Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId); | |
| if (Card == NULL) { | |
| Status = EFI_DEVICE_ERROR; | |
| goto ClosePciIo; | |
| } | |
| Private->Variant = Card->Variant; | |
| // | |
| // IsQxl is based on the detected Card->Variant, which at a later point might | |
| // not match Private->Variant. | |
| // | |
| IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS); | |
| // | |
| // Save original PCI attributes | |
| // | |
| Status = Private->PciIo->Attributes ( | |
| Private->PciIo, | |
| EfiPciIoAttributeOperationGet, | |
| 0, | |
| &Private->OriginalPciAttributes | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ClosePciIo; | |
| } | |
| // | |
| // Get supported PCI attributes | |
| // | |
| Status = Private->PciIo->Attributes ( | |
| Private->PciIo, | |
| EfiPciIoAttributeOperationSupported, | |
| 0, | |
| &SupportedVgaIo | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ClosePciIo; | |
| } | |
| SupportedVgaIo &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16); | |
| if ((SupportedVgaIo == 0) && IS_PCI_VGA (&Pci)) { | |
| Status = EFI_UNSUPPORTED; | |
| goto ClosePciIo; | |
| } | |
| // | |
| // Set new PCI attributes | |
| // | |
| Status = Private->PciIo->Attributes ( | |
| Private->PciIo, | |
| EfiPciIoAttributeOperationEnable, | |
| EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | SupportedVgaIo, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ClosePciIo; | |
| } | |
| // | |
| // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+). | |
| // | |
| if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) { | |
| EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc; | |
| Status = Private->PciIo->GetBarAttributes ( | |
| Private->PciIo, | |
| PCI_BAR_IDX2, | |
| NULL, | |
| (VOID **)&MmioDesc | |
| ); | |
| if (EFI_ERROR (Status) || | |
| (MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM)) | |
| { | |
| DEBUG ((DEBUG_INFO, "QemuVideo: No mmio bar, fallback to port io\n")); | |
| Private->Variant = QEMU_VIDEO_BOCHS; | |
| } else { | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "QemuVideo: Using mmio bar @ 0x%lx\n", | |
| MmioDesc->AddrRangeMin | |
| )); | |
| } | |
| if (!EFI_ERROR (Status)) { | |
| FreePool (MmioDesc); | |
| } | |
| } | |
| // | |
| // VMWare SVGA is handled like Bochs (with port IO only). | |
| // | |
| if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) { | |
| Private->Variant = QEMU_VIDEO_BOCHS; | |
| Private->FrameBufferVramBarIndex = PCI_BAR_IDX1; | |
| } | |
| // | |
| // Check if accessing the bochs interface works. | |
| // | |
| if ((Private->Variant == QEMU_VIDEO_BOCHS_MMIO) || | |
| (Private->Variant == QEMU_VIDEO_BOCHS)) | |
| { | |
| UINT16 BochsId; | |
| BochsId = BochsRead (Private, VBE_DISPI_INDEX_ID); | |
| if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) { | |
| DEBUG ((DEBUG_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId)); | |
| Status = EFI_DEVICE_ERROR; | |
| goto RestoreAttributes; | |
| } | |
| } | |
| // | |
| // Get ParentDevicePath | |
| // | |
| Status = gBS->HandleProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID **)&ParentDevicePath | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto RestoreAttributes; | |
| } | |
| // | |
| // Set Gop Device Path | |
| // | |
| ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH)); | |
| AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH; | |
| AcpiDeviceNode.Header.SubType = ACPI_ADR_DP; | |
| AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0); | |
| SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH)); | |
| Private->GopDevicePath = AppendDevicePathNode ( | |
| ParentDevicePath, | |
| (EFI_DEVICE_PATH_PROTOCOL *)&AcpiDeviceNode | |
| ); | |
| if (Private->GopDevicePath == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto RestoreAttributes; | |
| } | |
| // | |
| // Create new child handle and install the device path protocol on it. | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &Private->Handle, | |
| &gEfiDevicePathProtocolGuid, | |
| Private->GopDevicePath, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto FreeGopDevicePath; | |
| } | |
| // | |
| // Construct video mode buffer | |
| // | |
| switch (Private->Variant) { | |
| case QEMU_VIDEO_CIRRUS_5430: | |
| case QEMU_VIDEO_CIRRUS_5446: | |
| Status = QemuVideoCirrusModeSetup (Private); | |
| break; | |
| case QEMU_VIDEO_BOCHS_MMIO: | |
| case QEMU_VIDEO_BOCHS: | |
| Status = QemuVideoBochsModeSetup (Private, IsQxl); | |
| break; | |
| default: | |
| ASSERT (FALSE); | |
| Status = EFI_DEVICE_ERROR; | |
| break; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| goto UninstallGopDevicePath; | |
| } | |
| // | |
| // Start the GOP software stack. | |
| // | |
| Status = QemuVideoGraphicsOutputConstructor (Private); | |
| if (EFI_ERROR (Status)) { | |
| goto FreeModeData; | |
| } | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &Private->Handle, | |
| &gEfiGraphicsOutputProtocolGuid, | |
| &Private->GraphicsOutput, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto DestructQemuVideoGraphics; | |
| } | |
| // | |
| // Reference parent handle from child handle. | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| (VOID **)&ChildPciIo, | |
| This->DriverBindingHandle, | |
| Private->Handle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto UninstallGop; | |
| } | |
| gBS->RestoreTPL (OldTpl); | |
| return EFI_SUCCESS; | |
| UninstallGop: | |
| gBS->UninstallProtocolInterface ( | |
| Private->Handle, | |
| &gEfiGraphicsOutputProtocolGuid, | |
| &Private->GraphicsOutput | |
| ); | |
| DestructQemuVideoGraphics: | |
| QemuVideoGraphicsOutputDestructor (Private); | |
| FreeModeData: | |
| FreePool (Private->ModeData); | |
| UninstallGopDevicePath: | |
| gBS->UninstallProtocolInterface ( | |
| Private->Handle, | |
| &gEfiDevicePathProtocolGuid, | |
| Private->GopDevicePath | |
| ); | |
| FreeGopDevicePath: | |
| FreePool (Private->GopDevicePath); | |
| RestoreAttributes: | |
| Private->PciIo->Attributes ( | |
| Private->PciIo, | |
| EfiPciIoAttributeOperationSet, | |
| Private->OriginalPciAttributes, | |
| NULL | |
| ); | |
| ClosePciIo: | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| FreePrivate: | |
| FreePool (Private); | |
| RestoreTpl: | |
| gBS->RestoreTPL (OldTpl); | |
| return Status; | |
| } | |
| /** | |
| Stop this device | |
| @param This The USB bus driver binding protocol. | |
| @param Controller The controller to release. | |
| @param NumberOfChildren The number of children of this device that | |
| opened the controller BY_CHILD. | |
| @param ChildHandleBuffer The array of child handle. | |
| @retval EFI_SUCCESS The controller or children are stopped. | |
| @retval EFI_DEVICE_ERROR Failed to stop the driver. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| QemuVideoControllerDriverStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| { | |
| EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; | |
| EFI_STATUS Status; | |
| QEMU_VIDEO_PRIVATE_DATA *Private; | |
| if (NumberOfChildren == 0) { | |
| // | |
| // Close the PCI I/O Protocol | |
| // | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // free all resources for whose access we need the child handle, because the | |
| // child handle is going away | |
| // | |
| ASSERT (NumberOfChildren == 1); | |
| Status = gBS->OpenProtocol ( | |
| ChildHandleBuffer[0], | |
| &gEfiGraphicsOutputProtocolGuid, | |
| (VOID **)&GraphicsOutput, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Get our private context information | |
| // | |
| Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput); | |
| ASSERT (Private->Handle == ChildHandleBuffer[0]); | |
| QemuVideoGraphicsOutputDestructor (Private); | |
| // | |
| // Remove the GOP protocol interface from the system | |
| // | |
| Status = gBS->UninstallMultipleProtocolInterfaces ( | |
| Private->Handle, | |
| &gEfiGraphicsOutputProtocolGuid, | |
| &Private->GraphicsOutput, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Restore original PCI attributes | |
| // | |
| Private->PciIo->Attributes ( | |
| Private->PciIo, | |
| EfiPciIoAttributeOperationSet, | |
| Private->OriginalPciAttributes, | |
| NULL | |
| ); | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Private->Handle | |
| ); | |
| FreePool (Private->ModeData); | |
| gBS->UninstallProtocolInterface ( | |
| Private->Handle, | |
| &gEfiDevicePathProtocolGuid, | |
| Private->GopDevicePath | |
| ); | |
| FreePool (Private->GopDevicePath); | |
| // | |
| // Free our instance data | |
| // | |
| gBS->FreePool (Private); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| TODO: Add function description | |
| @param Private TODO: add argument description | |
| @param Address TODO: add argument description | |
| @param Data TODO: add argument description | |
| TODO: add return values | |
| **/ | |
| VOID | |
| outb ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINTN Address, | |
| UINT8 Data | |
| ) | |
| { | |
| Private->PciIo->Io.Write ( | |
| Private->PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| Address, | |
| 1, | |
| &Data | |
| ); | |
| } | |
| /** | |
| TODO: Add function description | |
| @param Private TODO: add argument description | |
| @param Address TODO: add argument description | |
| @param Data TODO: add argument description | |
| TODO: add return values | |
| **/ | |
| VOID | |
| outw ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINTN Address, | |
| UINT16 Data | |
| ) | |
| { | |
| Private->PciIo->Io.Write ( | |
| Private->PciIo, | |
| EfiPciIoWidthUint16, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| Address, | |
| 1, | |
| &Data | |
| ); | |
| } | |
| /** | |
| TODO: Add function description | |
| @param Private TODO: add argument description | |
| @param Address TODO: add argument description | |
| TODO: add return values | |
| **/ | |
| UINT8 | |
| inb ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINTN Address | |
| ) | |
| { | |
| UINT8 Data; | |
| Private->PciIo->Io.Read ( | |
| Private->PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| Address, | |
| 1, | |
| &Data | |
| ); | |
| return Data; | |
| } | |
| /** | |
| TODO: Add function description | |
| @param Private TODO: add argument description | |
| @param Address TODO: add argument description | |
| TODO: add return values | |
| **/ | |
| UINT16 | |
| inw ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINTN Address | |
| ) | |
| { | |
| UINT16 Data; | |
| Private->PciIo->Io.Read ( | |
| Private->PciIo, | |
| EfiPciIoWidthUint16, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| Address, | |
| 1, | |
| &Data | |
| ); | |
| return Data; | |
| } | |
| /** | |
| TODO: Add function description | |
| @param Private TODO: add argument description | |
| @param Index TODO: add argument description | |
| @param Red TODO: add argument description | |
| @param Green TODO: add argument description | |
| @param Blue TODO: add argument description | |
| TODO: add return values | |
| **/ | |
| VOID | |
| SetPaletteColor ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINTN Index, | |
| UINT8 Red, | |
| UINT8 Green, | |
| UINT8 Blue | |
| ) | |
| { | |
| VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8)Index); | |
| VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8)(Red >> 2)); | |
| VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8)(Green >> 2)); | |
| VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8)(Blue >> 2)); | |
| } | |
| /** | |
| TODO: Add function description | |
| @param Private TODO: add argument description | |
| TODO: add return values | |
| **/ | |
| VOID | |
| SetDefaultPalette ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private | |
| ) | |
| { | |
| UINTN Index; | |
| UINTN RedIndex; | |
| UINTN GreenIndex; | |
| UINTN BlueIndex; | |
| Index = 0; | |
| for (RedIndex = 0; RedIndex < 8; RedIndex++) { | |
| for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) { | |
| for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) { | |
| SetPaletteColor (Private, Index, (UINT8)(RedIndex << 5), (UINT8)(GreenIndex << 5), (UINT8)(BlueIndex << 6)); | |
| Index++; | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| TODO: Add function description | |
| @param Private TODO: add argument description | |
| TODO: add return values | |
| **/ | |
| VOID | |
| ClearScreen ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private | |
| ) | |
| { | |
| UINT32 Color; | |
| Color = 0; | |
| Private->PciIo->Mem.Write ( | |
| Private->PciIo, | |
| EfiPciIoWidthFillUint32, | |
| Private->FrameBufferVramBarIndex, | |
| 0, | |
| 0x400000 >> 2, | |
| &Color | |
| ); | |
| } | |
| /** | |
| TODO: Add function description | |
| @param Private TODO: add argument description | |
| TODO: add return values | |
| **/ | |
| VOID | |
| DrawLogo ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINTN ScreenWidth, | |
| UINTN ScreenHeight | |
| ) | |
| { | |
| } | |
| /** | |
| TODO: Add function description | |
| @param Private TODO: add argument description | |
| @param ModeData TODO: add argument description | |
| TODO: add return values | |
| **/ | |
| VOID | |
| InitializeCirrusGraphicsMode ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| QEMU_VIDEO_CIRRUS_MODES *ModeData | |
| ) | |
| { | |
| UINT8 Byte; | |
| UINTN Index; | |
| outw (Private, SEQ_ADDRESS_REGISTER, 0x1206); | |
| outw (Private, SEQ_ADDRESS_REGISTER, 0x0012); | |
| for (Index = 0; Index < 15; Index++) { | |
| outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]); | |
| } | |
| if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) { | |
| outb (Private, SEQ_ADDRESS_REGISTER, 0x0f); | |
| Byte = (UINT8)((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30); | |
| outb (Private, SEQ_DATA_REGISTER, Byte); | |
| } | |
| outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting); | |
| outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506); | |
| outw (Private, SEQ_ADDRESS_REGISTER, 0x0300); | |
| outw (Private, CRTC_ADDRESS_REGISTER, 0x2011); | |
| for (Index = 0; Index < 28; Index++) { | |
| outw (Private, CRTC_ADDRESS_REGISTER, (UINT16)((ModeData->CrtcSettings[Index] << 8) | Index)); | |
| } | |
| for (Index = 0; Index < 9; Index++) { | |
| outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16)((GraphicsController[Index] << 8) | Index)); | |
| } | |
| inb (Private, INPUT_STATUS_1_REGISTER); | |
| for (Index = 0; Index < 21; Index++) { | |
| outb (Private, ATT_ADDRESS_REGISTER, (UINT8)Index); | |
| outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]); | |
| } | |
| outb (Private, ATT_ADDRESS_REGISTER, 0x20); | |
| outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009); | |
| outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a); | |
| outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b); | |
| outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff); | |
| SetDefaultPalette (Private); | |
| ClearScreen (Private); | |
| } | |
| VOID | |
| BochsWrite ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINT16 Reg, | |
| UINT16 Data | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) { | |
| Status = Private->PciIo->Mem.Write ( | |
| Private->PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_BAR_IDX2, | |
| 0x500 + (Reg << 1), | |
| 1, | |
| &Data | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } else { | |
| outw (Private, VBE_DISPI_IOPORT_INDEX, Reg); | |
| outw (Private, VBE_DISPI_IOPORT_DATA, Data); | |
| } | |
| } | |
| UINT16 | |
| BochsRead ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINT16 Reg | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT16 Data; | |
| if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) { | |
| Status = Private->PciIo->Mem.Read ( | |
| Private->PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_BAR_IDX2, | |
| 0x500 + (Reg << 1), | |
| 1, | |
| &Data | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } else { | |
| outw (Private, VBE_DISPI_IOPORT_INDEX, Reg); | |
| Data = inw (Private, VBE_DISPI_IOPORT_DATA); | |
| } | |
| return Data; | |
| } | |
| VOID | |
| VgaOutb ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINTN Reg, | |
| UINT8 Data | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) { | |
| Status = Private->PciIo->Mem.Write ( | |
| Private->PciIo, | |
| EfiPciIoWidthUint8, | |
| PCI_BAR_IDX2, | |
| 0x400 - 0x3c0 + Reg, | |
| 1, | |
| &Data | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } else { | |
| outb (Private, Reg, Data); | |
| } | |
| } | |
| STATIC | |
| UINT8 | |
| VgaInb ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| UINTN Reg | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT8 Data; | |
| if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) { | |
| Data = 0; | |
| Status = Private->PciIo->Mem.Read ( | |
| Private->PciIo, | |
| EfiPciIoWidthUint8, | |
| PCI_BAR_IDX2, | |
| 0x400 - 0x3c0 + Reg, | |
| 1, | |
| &Data | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } else { | |
| Data = inb (Private, Reg); | |
| } | |
| return Data; | |
| } | |
| VOID | |
| InitializeBochsGraphicsMode ( | |
| QEMU_VIDEO_PRIVATE_DATA *Private, | |
| QEMU_VIDEO_MODE_DATA *ModeData | |
| ) | |
| { | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "InitializeBochsGraphicsMode: %dx%d @ %d\n", | |
| ModeData->HorizontalResolution, | |
| ModeData->VerticalResolution, | |
| ModeData->ColorDepth | |
| )); | |
| /* set color mode */ | |
| VgaOutb (Private, MISC_OUTPUT_REGISTER, 0x01); | |
| /* reset flip flop + unblank */ | |
| VgaInb (Private, INPUT_STATUS_1_REGISTER); | |
| VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20); | |
| BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, 0); | |
| BochsWrite (Private, VBE_DISPI_INDEX_BANK, 0); | |
| BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET, 0); | |
| BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET, 0); | |
| BochsWrite (Private, VBE_DISPI_INDEX_BPP, (UINT16)ModeData->ColorDepth); | |
| BochsWrite (Private, VBE_DISPI_INDEX_XRES, (UINT16)ModeData->HorizontalResolution); | |
| BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH, (UINT16)ModeData->HorizontalResolution); | |
| BochsWrite (Private, VBE_DISPI_INDEX_YRES, (UINT16)ModeData->VerticalResolution); | |
| BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16)ModeData->VerticalResolution); | |
| BochsWrite ( | |
| Private, | |
| VBE_DISPI_INDEX_ENABLE, | |
| VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED | |
| ); | |
| SetDefaultPalette (Private); | |
| ClearScreen (Private); | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| InitializeQemuVideo ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gQemuVideoDriverBinding, | |
| ImageHandle, | |
| &gQemuVideoComponentName, | |
| &gQemuVideoComponentName2 | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } |