| /** @file | |
| BiosVideo driver produce EFI_GRAPHIC_OUTPUT_PROTOCOL via LegacyBios Video rom. | |
| Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "BiosVideo.h" | |
| // | |
| // EFI Driver Binding Protocol Instance | |
| // | |
| EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = { | |
| BiosVideoDriverBindingSupported, | |
| BiosVideoDriverBindingStart, | |
| BiosVideoDriverBindingStop, | |
| 0x3, | |
| NULL, | |
| NULL | |
| }; | |
| // | |
| // Global lookup tables for VGA graphics modes | |
| // | |
| UINT8 mVgaLeftMaskTable[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; | |
| UINT8 mVgaRightMaskTable[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; | |
| UINT8 mVgaBitMaskTable[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; | |
| EFI_LEGACY_8259_PROTOCOL *mLegacy8259 = NULL; | |
| THUNK_CONTEXT mThunkContext; | |
| EFI_GRAPHICS_OUTPUT_BLT_PIXEL mVgaColorToGraphicsOutputColor[] = { | |
| // | |
| // {B, G, R, reserved} | |
| // | |
| {0x00, 0x00, 0x00, 0x00}, // BLACK | |
| {0x98, 0x00, 0x00, 0x00}, // LIGHTBLUE | |
| {0x00, 0x98, 0x00, 0x00}, // LIGHGREEN | |
| {0x98, 0x98, 0x00, 0x00}, // LIGHCYAN | |
| {0x00, 0x00, 0x98, 0x00}, // LIGHRED | |
| {0x98, 0x00, 0x98, 0x00}, // MAGENTA | |
| {0x00, 0x98, 0x98, 0x00}, // BROWN | |
| {0x98, 0x98, 0x98, 0x00}, // LIGHTGRAY | |
| {0x10, 0x10, 0x10, 0x00}, | |
| {0xff, 0x10, 0x10, 0x00}, // BLUE | |
| {0x10, 0xff, 0x10, 0x00}, // LIME | |
| {0xff, 0xff, 0x10, 0x00}, // CYAN | |
| {0x10, 0x10, 0xff, 0x00}, // RED | |
| {0xf0, 0x10, 0xff, 0x00}, // FUCHSIA | |
| {0x10, 0xff, 0xff, 0x00}, // YELLOW | |
| {0xff, 0xff, 0xff, 0x00} // WHITE | |
| }; | |
| // | |
| // Standard timing defined by VESA EDID | |
| // | |
| VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming[] = { | |
| // | |
| // Established Timing I | |
| // | |
| {800, 600, 60}, | |
| {800, 600, 56}, | |
| {640, 480, 75}, | |
| {640, 480, 72}, | |
| {640, 480, 67}, | |
| {640, 480, 60}, | |
| {720, 400, 88}, | |
| {720, 400, 70}, | |
| // | |
| // Established Timing II | |
| // | |
| {1280, 1024, 75}, | |
| {1024, 768, 75}, | |
| {1024, 768, 70}, | |
| {1024, 768, 60}, | |
| {1024, 768, 87}, | |
| {832, 624, 75}, | |
| {800, 600, 75}, | |
| {800, 600, 72}, | |
| // | |
| // Established Timing III | |
| // | |
| {1152, 870, 75} | |
| }; | |
| /** | |
| Install child handle for a detect BiosVideo device and install related protocol | |
| into this handle, such as EFI_GRAPHIC_OUTPUT_PROTOCOL. | |
| @param This Instance pointer of EFI_DRIVER_BINDING_PROTOCOL | |
| @param ParentHandle Parent's controller handle | |
| @param ParentPciIo Parent's EFI_PCI_IO_PROTOCOL instance pointer | |
| @param ParentLegacy8259 Parent's EFI_LEGACY_8259_PROTOCOL instance pointer | |
| @param ParentDevicePath Parent's BIOS Video controller device path | |
| @param RemainingDevicePath Remaining device path node instance for children. | |
| @return whether success to create children handle for a VGA device and install | |
| related protocol into new children handle. | |
| **/ | |
| EFI_STATUS | |
| BiosVideoChildHandleInstall ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ParentHandle, | |
| IN EFI_PCI_IO_PROTOCOL *ParentPciIo, | |
| IN EFI_LEGACY_8259_PROTOCOL *ParentLegacy8259, | |
| IN THUNK_CONTEXT *ThunkContext, | |
| IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| ; | |
| /** | |
| Deregister an video child handle and free resources | |
| @param This Protocol instance pointer. | |
| @param Controller Video controller handle | |
| @param Handle Video child handle | |
| @return EFI_STATUS | |
| **/ | |
| EFI_STATUS | |
| BiosVideoChildHandleUninstall ( | |
| EFI_DRIVER_BINDING_PROTOCOL *This, | |
| EFI_HANDLE Controller, | |
| EFI_HANDLE Handle | |
| ) | |
| ; | |
| /** | |
| Collect the resource from destroyed bios video device. | |
| @param BiosVideoPrivate Video child device private data structure | |
| **/ | |
| VOID | |
| BiosVideoDeviceReleaseResource ( | |
| BIOS_VIDEO_DEV *BiosVideoPrivate | |
| ) | |
| ; | |
| /** | |
| Driver Entry Point. | |
| @param ImageHandle Handle of driver image. | |
| @param SystemTable Pointer to system table. | |
| @return EFI_STATUS | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoDriverEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gBiosVideoDriverBinding, | |
| ImageHandle, | |
| &gBiosVideoComponentName, | |
| &gBiosVideoComponentName2 | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Test to see if Bios Video could be supported on the Controller. | |
| @param This Pointer to driver binding protocol | |
| @param Controller Controller handle to connect | |
| @param RemainingDevicePath A pointer to the remaining portion of a device path | |
| @retval EFI_SUCCESS This driver supports this device. | |
| @retval other This driver does not support this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoDriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_LEGACY_8259_PROTOCOL *LegacyBios; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| // | |
| // See if the Legacy 8259 Protocol is available | |
| // | |
| Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &LegacyBios); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Open the IO Abstraction(s) needed to perform the supported test | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| (VOID **) &PciIo, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| if (!BiosVideoIsVga (PciIo)) { | |
| Status = EFI_UNSUPPORTED; | |
| } | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Install Graphics Output Protocol onto VGA device handles | |
| @param This Pointer to driver binding protocol | |
| @param Controller Controller handle to connect | |
| @param RemainingDevicePath A pointer to the remaining portion of a device path | |
| @return EFI_STATUS | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoDriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| PciIo = NULL; | |
| // | |
| // Prepare for status code | |
| // | |
| Status = gBS->HandleProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID **) &ParentDevicePath | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Open the IO Abstraction(s) needed | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| (VOID **) &PciIo, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Establish legacy environment for thunk call for all children handle. | |
| // | |
| if (mLegacy8259 == NULL) { | |
| Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &mLegacy8259); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| InitializeBiosIntCaller(&mThunkContext); | |
| InitializeInterruptRedirection(mLegacy8259); | |
| } | |
| // | |
| // Create child handle and install GraphicsOutputProtocol on it | |
| // | |
| Status = BiosVideoChildHandleInstall ( | |
| This, | |
| Controller, | |
| PciIo, | |
| mLegacy8259, | |
| &mThunkContext, | |
| ParentDevicePath, | |
| RemainingDevicePath | |
| ); | |
| Done: | |
| if (EFI_ERROR (Status)) { | |
| if (PciIo != NULL) { | |
| // | |
| // Release PCI I/O Protocols on the controller handle. | |
| // | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Stop this driver on Controller | |
| @param This Protocol instance pointer. | |
| @param Controller Handle of device to stop driver on | |
| @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of | |
| children is zero stop the entire bus driver. | |
| @param ChildHandleBuffer List of Child Handles to Stop. | |
| @retval EFI_SUCCESS This driver is removed Controller. | |
| @retval other This driver was not removed from this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoDriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| BOOLEAN AllChildrenStopped; | |
| UINTN Index; | |
| if (NumberOfChildren == 0) { | |
| // | |
| // Close PCI I/O protocol on the controller handle | |
| // | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| AllChildrenStopped = TRUE; | |
| for (Index = 0; Index < NumberOfChildren; Index++) { | |
| Status = BiosVideoChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]); | |
| if (EFI_ERROR (Status)) { | |
| AllChildrenStopped = FALSE; | |
| } | |
| } | |
| if (!AllChildrenStopped) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Install child handle for a detect BiosVideo device and install related protocol | |
| into this handle, such as EFI_GRAPHIC_OUTPUT_PROTOCOL. | |
| @param This Instance pointer of EFI_DRIVER_BINDING_PROTOCOL | |
| @param ParentHandle Parent's controller handle | |
| @param ParentPciIo Parent's EFI_PCI_IO_PROTOCOL instance pointer | |
| @param ParentLegacy8259 Parent's EFI_LEGACY_8259_PROTOCOL instance pointer | |
| @param ParentDevicePath Parent's BIOS Video controller device path | |
| @param RemainingDevicePath Remaining device path node instance for children. | |
| @return whether success to create children handle for a VGA device and install | |
| related protocol into new children handle. | |
| **/ | |
| EFI_STATUS | |
| BiosVideoChildHandleInstall ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE ParentHandle, | |
| IN EFI_PCI_IO_PROTOCOL *ParentPciIo, | |
| IN EFI_LEGACY_8259_PROTOCOL *ParentLegacy8259, | |
| IN THUNK_CONTEXT *ParentThunkContext, | |
| IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| BIOS_VIDEO_DEV *BiosVideoPrivate; | |
| ACPI_ADR_DEVICE_PATH AcpiDeviceNode; | |
| // | |
| // Allocate the private device structure for video device | |
| // | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (BIOS_VIDEO_DEV), | |
| (VOID**) &BiosVideoPrivate | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| ZeroMem (BiosVideoPrivate, sizeof (BIOS_VIDEO_DEV)); | |
| if (!BiosVideoIsVga (ParentPciIo)) { | |
| Status = EFI_UNSUPPORTED; | |
| goto Done; | |
| } | |
| BiosVideoPrivate->VgaCompatible = TRUE; | |
| // | |
| // Initialize the child private structure | |
| // | |
| BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE; | |
| BiosVideoPrivate->Handle = NULL; | |
| // | |
| // Fill in Graphics Output specific mode structures | |
| // | |
| BiosVideoPrivate->HardwareNeedsStarting = TRUE; | |
| BiosVideoPrivate->ModeData = NULL; | |
| BiosVideoPrivate->LineBuffer = NULL; | |
| BiosVideoPrivate->VgaFrameBuffer = NULL; | |
| BiosVideoPrivate->VbeFrameBuffer = NULL; | |
| // | |
| // Fill in the VGA Mini Port Protocol fields | |
| // | |
| BiosVideoPrivate->VgaMiniPort.SetMode = BiosVideoVgaMiniPortSetMode; | |
| BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset = 0xb8000; | |
| BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4; | |
| BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset = 0x3d5; | |
| BiosVideoPrivate->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR; | |
| BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR; | |
| BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR; | |
| // | |
| // Assume that Graphics Output Protocol will be produced until proven otherwise | |
| // | |
| BiosVideoPrivate->ProduceGraphicsOutput = TRUE; | |
| // | |
| // Child handle need to consume the Legacy Bios protocol | |
| // | |
| BiosVideoPrivate->Legacy8259 = ParentLegacy8259; | |
| BiosVideoPrivate->ThunkContext = ParentThunkContext; | |
| // | |
| // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally | |
| // | |
| BiosVideoPrivate->PciIo = ParentPciIo; | |
| // | |
| // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output | |
| // | |
| Status = BiosVideoCheckForVbe (BiosVideoPrivate); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support | |
| // for the standard 640x480 16 color VGA mode | |
| // | |
| if (BiosVideoPrivate->VgaCompatible) { | |
| Status = BiosVideoCheckForVga (BiosVideoPrivate); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do | |
| // not produce the Graphics Output protocol. Instead, produce the VGA MiniPort Protocol. | |
| // | |
| BiosVideoPrivate->ProduceGraphicsOutput = FALSE; | |
| // | |
| // INT services are available, so on the 80x25 and 80x50 text mode are supported | |
| // | |
| BiosVideoPrivate->VgaMiniPort.MaxMode = 2; | |
| } | |
| } | |
| if (BiosVideoPrivate->ProduceGraphicsOutput) { | |
| if (RemainingDevicePath == NULL) { | |
| 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)); | |
| BiosVideoPrivate->DevicePath = AppendDevicePathNode ( | |
| ParentDevicePath, | |
| (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode | |
| ); | |
| } else { | |
| BiosVideoPrivate->DevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath); | |
| } | |
| // | |
| // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &BiosVideoPrivate->Handle, | |
| &gEfiDevicePathProtocolGuid, | |
| BiosVideoPrivate->DevicePath, | |
| &gEfiGraphicsOutputProtocolGuid, | |
| &BiosVideoPrivate->GraphicsOutput, | |
| &gEfiEdidDiscoveredProtocolGuid, | |
| &BiosVideoPrivate->EdidDiscovered, | |
| &gEfiEdidActiveProtocolGuid, | |
| &BiosVideoPrivate->EdidActive, | |
| NULL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Open the Parent Handle for the child | |
| // | |
| Status = gBS->OpenProtocol ( | |
| ParentHandle, | |
| &gEfiPciIoProtocolGuid, | |
| (VOID **) &BiosVideoPrivate->PciIo, | |
| This->DriverBindingHandle, | |
| BiosVideoPrivate->Handle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| } | |
| } else { | |
| // | |
| // Install VGA Mini Port Protocol | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &BiosVideoPrivate->Handle, | |
| &gEfiVgaMiniPortProtocolGuid, | |
| &BiosVideoPrivate->VgaMiniPort, | |
| NULL | |
| ); | |
| } | |
| Done: | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Free private data structure | |
| // | |
| BiosVideoDeviceReleaseResource (BiosVideoPrivate); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Deregister an video child handle and free resources | |
| @param This Protocol instance pointer. | |
| @param Controller Video controller handle | |
| @param Handle Video child handle | |
| @return EFI_STATUS | |
| **/ | |
| EFI_STATUS | |
| BiosVideoChildHandleUninstall ( | |
| EFI_DRIVER_BINDING_PROTOCOL *This, | |
| EFI_HANDLE Controller, | |
| EFI_HANDLE Handle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| IA32_REGISTER_SET Regs; | |
| EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; | |
| EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort; | |
| BIOS_VIDEO_DEV *BiosVideoPrivate; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| BiosVideoPrivate = NULL; | |
| Status = gBS->OpenProtocol ( | |
| Handle, | |
| &gEfiGraphicsOutputProtocolGuid, | |
| (VOID **) &GraphicsOutput, | |
| This->DriverBindingHandle, | |
| Handle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput); | |
| } | |
| Status = gBS->OpenProtocol ( | |
| Handle, | |
| &gEfiVgaMiniPortProtocolGuid, | |
| (VOID **) &VgaMiniPort, | |
| This->DriverBindingHandle, | |
| Handle, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort); | |
| } | |
| if (BiosVideoPrivate == NULL) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Close PCI I/O protocol that opened by child handle | |
| // | |
| Status = gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Handle | |
| ); | |
| // | |
| // Uninstall protocols on child handle | |
| // | |
| if (BiosVideoPrivate->ProduceGraphicsOutput) { | |
| Status = gBS->UninstallMultipleProtocolInterfaces ( | |
| BiosVideoPrivate->Handle, | |
| &gEfiDevicePathProtocolGuid, | |
| BiosVideoPrivate->DevicePath, | |
| &gEfiGraphicsOutputProtocolGuid, | |
| &BiosVideoPrivate->GraphicsOutput, | |
| &gEfiEdidDiscoveredProtocolGuid, | |
| &BiosVideoPrivate->EdidDiscovered, | |
| &gEfiEdidActiveProtocolGuid, | |
| &BiosVideoPrivate->EdidActive, | |
| NULL | |
| ); | |
| } else { | |
| Status = gBS->UninstallMultipleProtocolInterfaces ( | |
| BiosVideoPrivate->Handle, | |
| &gEfiVgaMiniPortProtocolGuid, | |
| &BiosVideoPrivate->VgaMiniPort, | |
| NULL | |
| ); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| (VOID **) &PciIo, | |
| This->DriverBindingHandle, | |
| Handle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| return Status; | |
| } | |
| gBS->SetMem (&Regs, sizeof (Regs), 0); | |
| // | |
| // Set the 80x25 Text VGA Mode | |
| // | |
| Regs.H.AH = 0x00; | |
| Regs.H.AL = 0x03; | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| Regs.H.AH = 0x11; | |
| Regs.H.AL = 0x14; | |
| Regs.H.BL = 0; | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| // | |
| // Do not disable IO/memory decode since that would prevent legacy ROM from working | |
| // | |
| // | |
| // Release all allocated resources | |
| // | |
| BiosVideoDeviceReleaseResource (BiosVideoPrivate); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Collect the resource from destroyed bios video device. | |
| @param BiosVideoPrivate Video child device private data structure | |
| **/ | |
| VOID | |
| BiosVideoDeviceReleaseResource ( | |
| BIOS_VIDEO_DEV *BiosVideoPrivate | |
| ) | |
| { | |
| if (BiosVideoPrivate == NULL) { | |
| return ; | |
| } | |
| // | |
| // Release all the resourses occupied by the BIOS_VIDEO_DEV | |
| // | |
| // | |
| // Free VGA Frame Buffer | |
| // | |
| if (BiosVideoPrivate->VgaFrameBuffer != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->VgaFrameBuffer); | |
| } | |
| // | |
| // Free VBE Frame Buffer | |
| // | |
| if (BiosVideoPrivate->VbeFrameBuffer != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->VbeFrameBuffer); | |
| } | |
| // | |
| // Free line buffer | |
| // | |
| if (BiosVideoPrivate->LineBuffer != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->LineBuffer); | |
| } | |
| // | |
| // Free mode data | |
| // | |
| if (BiosVideoPrivate->ModeData != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->ModeData); | |
| } | |
| // | |
| // Free memory allocated below 1MB | |
| // | |
| if (BiosVideoPrivate->PagesBelow1MB != 0) { | |
| gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB); | |
| } | |
| if (BiosVideoPrivate->VbeSaveRestorePages != 0) { | |
| gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages); | |
| } | |
| // | |
| // Free graphics output protocol occupied resource | |
| // | |
| if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) { | |
| if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info); | |
| } | |
| gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode); | |
| } | |
| // | |
| // Free EDID discovered protocol occupied resource | |
| // | |
| if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->EdidDiscovered.Edid); | |
| } | |
| // | |
| // Free EDID active protocol occupied resource | |
| // | |
| if (BiosVideoPrivate->EdidActive.Edid != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->EdidActive.Edid); | |
| } | |
| if (BiosVideoPrivate->DevicePath!= NULL) { | |
| gBS->FreePool (BiosVideoPrivate->DevicePath); | |
| } | |
| gBS->FreePool (BiosVideoPrivate); | |
| return ; | |
| } | |
| /** | |
| Generate a search key for a specified timing data. | |
| @param EdidTiming - Pointer to EDID timing | |
| @return The 32 bit unique key for search. | |
| **/ | |
| STATIC | |
| UINT32 | |
| CalculateEdidKey ( | |
| VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming | |
| ) | |
| { | |
| UINT32 Key; | |
| // | |
| // Be sure no conflicts for all standard timing defined by VESA. | |
| // | |
| Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution; | |
| return Key; | |
| } | |
| /** | |
| Parse the Established Timing and Standard Timing in EDID data block. | |
| @param EdidBuffer - Pointer to EDID data block | |
| @param ValidEdidTiming - Valid EDID timing information | |
| @return TRUE - The EDID data is valid. | |
| FALSE - The EDID data is invalid. | |
| **/ | |
| STATIC | |
| BOOLEAN | |
| ParseEdidData ( | |
| UINT8 *EdidBuffer, | |
| VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming | |
| ) | |
| { | |
| UINT8 CheckSum; | |
| UINT32 Index; | |
| UINT32 ValidNumber; | |
| UINT32 TimingBits; | |
| UINT8 *BufferIndex; | |
| UINT16 HorizontalResolution; | |
| UINT16 VerticalResolution; | |
| UINT8 AspectRatio; | |
| UINT8 RefreshRate; | |
| VESA_BIOS_EXTENSIONS_EDID_TIMING TempTiming; | |
| VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock; | |
| EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidBuffer; | |
| // | |
| // Check the checksum of EDID data | |
| // | |
| CheckSum = 0; | |
| for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; Index ++) { | |
| CheckSum = (UINT8)(CheckSum + EdidBuffer[Index]); | |
| } | |
| if (CheckSum != 0) { | |
| return FALSE; | |
| } | |
| ValidNumber = 0; | |
| gBS->SetMem (ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING), 0); | |
| if ((EdidDataBlock->EstablishedTimings[0] != 0) || | |
| (EdidDataBlock->EstablishedTimings[1] != 0) || | |
| (EdidDataBlock->EstablishedTimings[2] != 0) | |
| ) { | |
| // | |
| // Established timing data | |
| // | |
| TimingBits = EdidDataBlock->EstablishedTimings[0] | | |
| (EdidDataBlock->EstablishedTimings[1] << 8) | | |
| ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ; | |
| for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) { | |
| if (TimingBits & 0x1) { | |
| ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]); | |
| ValidNumber ++; | |
| } | |
| TimingBits = TimingBits >> 1; | |
| } | |
| } else { | |
| // | |
| // If no Established timing data, read the standard timing data | |
| // | |
| BufferIndex = &EdidDataBlock->StandardTimingIdentification[0]; | |
| for (Index = 0; Index < 8; Index ++) { | |
| if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){ | |
| // | |
| // A valid Standard Timing | |
| // | |
| HorizontalResolution = (UINT8) (BufferIndex[0] * 8 + 248); | |
| AspectRatio = (UINT8) (BufferIndex[1] >> 6); | |
| switch (AspectRatio) { | |
| case 0: | |
| VerticalResolution = (UINT8) (HorizontalResolution / 16 * 10); | |
| break; | |
| case 1: | |
| VerticalResolution = (UINT8) (HorizontalResolution / 4 * 3); | |
| break; | |
| case 2: | |
| VerticalResolution = (UINT8) (HorizontalResolution / 5 * 4); | |
| break; | |
| case 3: | |
| VerticalResolution = (UINT8) (HorizontalResolution / 16 * 9); | |
| break; | |
| default: | |
| VerticalResolution = (UINT8) (HorizontalResolution / 4 * 3); | |
| break; | |
| } | |
| RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60); | |
| TempTiming.HorizontalResolution = HorizontalResolution; | |
| TempTiming.VerticalResolution = VerticalResolution; | |
| TempTiming.RefreshRate = RefreshRate; | |
| ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming); | |
| ValidNumber ++; | |
| } | |
| BufferIndex += 2; | |
| } | |
| } | |
| ValidEdidTiming->ValidNumber = ValidNumber; | |
| return TRUE; | |
| } | |
| /** | |
| Search a specified Timing in all the valid EDID timings. | |
| @param ValidEdidTiming - All valid EDID timing information. | |
| @param EdidTiming - The Timing to search for. | |
| @return TRUE - Found. | |
| FALSE - Not found. | |
| **/ | |
| STATIC | |
| BOOLEAN | |
| SearchEdidTiming ( | |
| VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming, | |
| VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming | |
| ) | |
| { | |
| UINT32 Index; | |
| UINT32 Key; | |
| Key = CalculateEdidKey (EdidTiming); | |
| for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) { | |
| if (Key == ValidEdidTiming->Key[Index]) { | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| #define PCI_DEVICE_ENABLED (EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_MEMORY_SPACE) | |
| /** | |
| Judge whether this device is VGA device. | |
| @param PciIo Parent PciIo protocol instance pointer | |
| @retval TRUE Is vga device | |
| @retval FALSE Is no vga device | |
| **/ | |
| BOOLEAN | |
| BiosVideoIsVga ( | |
| IN EFI_PCI_IO_PROTOCOL *PciIo | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| BOOLEAN VgaCompatible; | |
| PCI_TYPE00 Pci; | |
| VgaCompatible = FALSE; | |
| // | |
| // Read the PCI Configuration Header | |
| // | |
| Status = PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| 0, | |
| sizeof (Pci) / sizeof (UINT32), | |
| &Pci | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return VgaCompatible; | |
| } | |
| // | |
| // See if this is a VGA compatible controller or not | |
| // | |
| if ((Pci.Hdr.Command & PCI_DEVICE_ENABLED) == PCI_DEVICE_ENABLED) { | |
| if (Pci.Hdr.ClassCode[2] == PCI_CLASS_OLD && Pci.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA) { | |
| // | |
| // Base Class 0x00 Sub-Class 0x01 - Backward compatible VGA device | |
| // | |
| VgaCompatible = TRUE; | |
| } | |
| if (Pci.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY && Pci.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA && Pci.Hdr.ClassCode[0] == 0x00) { | |
| // | |
| // Base Class 3 Sub-Class 0 Programming interface 0 - VGA compatible Display controller | |
| // | |
| VgaCompatible = TRUE; | |
| } | |
| } | |
| return VgaCompatible; | |
| } | |
| /** | |
| Check for VBE device | |
| @param BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure | |
| @retval EFI_SUCCESS VBE device found | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoCheckForVbe ( | |
| IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| IA32_REGISTER_SET Regs; | |
| UINT16 *ModeNumberPtr; | |
| BOOLEAN ModeFound; | |
| BOOLEAN EdidFound; | |
| BIOS_VIDEO_MODE_DATA *ModeBuffer; | |
| BIOS_VIDEO_MODE_DATA *CurrentModeData; | |
| UINTN PreferMode; | |
| UINTN ModeNumber; | |
| VESA_BIOS_EXTENSIONS_EDID_TIMING Timing; | |
| VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming; | |
| EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *GraphicsOutputMode; | |
| // | |
| // Allocate buffer under 1MB for VBE data structures | |
| // | |
| BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES ( | |
| sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) + | |
| sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) + | |
| sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) + | |
| sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK) | |
| ); | |
| BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1; | |
| Status = gBS->AllocatePages ( | |
| AllocateMaxAddress, | |
| EfiBootServicesData, | |
| BiosVideoPrivate->NumberOfPagesBelow1MB, | |
| &BiosVideoPrivate->PagesBelow1MB | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING)); | |
| // | |
| // Fill in the Graphics Output Protocol | |
| // | |
| BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode; | |
| BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode; | |
| BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVbeBlt; | |
| BiosVideoPrivate->GraphicsOutput.Mode = NULL; | |
| // | |
| // Fill in the VBE related data structures | |
| // | |
| BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB); | |
| BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1); | |
| BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1); | |
| BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1); | |
| BiosVideoPrivate->VbeSaveRestorePages = 0; | |
| BiosVideoPrivate->VbeSaveRestoreBuffer = 0; | |
| // | |
| // Test to see if the Video Adapter is compliant with VBE 3.0 | |
| // | |
| // INT 10 - VESA SuperVGA BIOS (VBE) - GET SuperVGA INFORMATION | |
| // | |
| // AX = 4F00h | |
| // ES:DI -> buffer for SuperVGA information (see #00077) | |
| // Return: AL = 4Fh if function supported | |
| // AH = status | |
| // 00h successful | |
| // ES:DI buffer filled | |
| // 01h failed | |
| // ---VBE v2.0--- | |
| // 02h function not supported by current hardware configuration | |
| // 03h function invalid in current video mode | |
| // Desc: determine whether VESA BIOS extensions are present and the capabilities | |
| // supported by the display adapter | |
| // | |
| gBS->SetMem (&Regs, sizeof (Regs), 0); | |
| Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION; | |
| gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0); | |
| BiosVideoPrivate->VbeInformationBlock->VESASignature = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE; | |
| Regs.E.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock); | |
| Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock); | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| Status = EFI_DEVICE_ERROR; | |
| // | |
| // See if the VESA call succeeded | |
| // | |
| if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) { | |
| return Status; | |
| } | |
| // | |
| // Check for 'VESA' signature | |
| // | |
| if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) { | |
| return Status; | |
| } | |
| // | |
| // Check to see if this is VBE 2.0 or higher | |
| // | |
| if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) { | |
| return Status; | |
| } | |
| // | |
| // Read EDID information | |
| // | |
| // INT 10 - VESA VBE/DC (Display Data Channel) - READ EDID | |
| // | |
| // AX = 4F15h | |
| // BL = 01h | |
| // CX = 0000h | |
| // DX = 0000h | |
| // ES:DI -> 128-byte buffer for EDID record (see #00127) | |
| // Return: AL = 4Fh if function supported | |
| // AH = status | |
| // 00h successful | |
| // ES:DI buffer filled | |
| // 01h failed (e.g. non-DDC monitor) | |
| // | |
| gBS->SetMem (&Regs, sizeof (Regs), 0); | |
| Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID; | |
| Regs.X.BX = 1; | |
| Regs.X.CX = 0; | |
| Regs.X.DX = 0; | |
| Regs.E.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock); | |
| Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeEdidDataBlock); | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| // | |
| // See if the VESA call succeeded | |
| // | |
| EdidFound = FALSE; | |
| if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) { | |
| // | |
| // Parse EDID data structure to retrieve modes supported by monitor | |
| // | |
| if (ParseEdidData ((UINT8 *) BiosVideoPrivate->VbeEdidDataBlock, &ValidEdidTiming) == TRUE) { | |
| EdidFound = TRUE; | |
| BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE, | |
| (VOID**) &BiosVideoPrivate->EdidDiscovered.Edid | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| gBS->CopyMem ( | |
| BiosVideoPrivate->EdidDiscovered.Edid, | |
| BiosVideoPrivate->VbeEdidDataBlock, | |
| VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE | |
| ); | |
| BiosVideoPrivate->EdidActive.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE, | |
| (VOID**)&BiosVideoPrivate->EdidActive.Edid | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| gBS->CopyMem ( | |
| BiosVideoPrivate->EdidActive.Edid, | |
| BiosVideoPrivate->VbeEdidDataBlock, | |
| VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE | |
| ); | |
| } else { | |
| BiosVideoPrivate->EdidDiscovered.SizeOfEdid = 0; | |
| BiosVideoPrivate->EdidDiscovered.Edid = NULL; | |
| BiosVideoPrivate->EdidActive.SizeOfEdid = 0; | |
| BiosVideoPrivate->EdidActive.Edid = NULL; | |
| } | |
| } | |
| // | |
| // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode | |
| // | |
| ModeNumberPtr = (UINT16 *) | |
| ( | |
| (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) | | |
| ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff) | |
| ); | |
| PreferMode = 0; | |
| ModeNumber = 0; | |
| for (; *ModeNumberPtr != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST; ModeNumberPtr++) { | |
| // | |
| // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number. | |
| // | |
| if ((*ModeNumberPtr & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) { | |
| continue; | |
| } | |
| // | |
| // Get the information about the mode | |
| // | |
| // INT 10 - VESA SuperVGA BIOS - GET SuperVGA MODE INFORMATION | |
| // | |
| // AX = 4F01h | |
| // CX = SuperVGA video mode (see #04082 for bitfields) | |
| // ES:DI -> 256-byte buffer for mode information (see #00079) | |
| // Return: AL = 4Fh if function supported | |
| // AH = status | |
| // 00h successful | |
| // ES:DI buffer filled | |
| // 01h failed | |
| // Desc: determine the attributes of the specified video mode | |
| // | |
| gBS->SetMem (&Regs, sizeof (Regs), 0); | |
| Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION; | |
| Regs.X.CX = *ModeNumberPtr; | |
| gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0); | |
| Regs.E.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock); | |
| Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock); | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| // | |
| // See if the call succeeded. If it didn't, then try the next mode. | |
| // | |
| if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) { | |
| continue; | |
| } | |
| // | |
| // See if the mode supports color. If it doesn't then try the next mode. | |
| // | |
| if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) { | |
| continue; | |
| } | |
| // | |
| // See if the mode supports graphics. If it doesn't then try the next mode. | |
| // | |
| if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) { | |
| continue; | |
| } | |
| // | |
| // See if the mode supports a linear frame buffer. If it doesn't then try the next mode. | |
| // | |
| if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) { | |
| continue; | |
| } | |
| // | |
| // See if the mode supports 32 bit color. If it doesn't then try the next mode. | |
| // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the | |
| // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel | |
| // | |
| if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) { | |
| continue; | |
| } | |
| if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) { | |
| continue; | |
| } | |
| if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) { | |
| continue; | |
| } | |
| // | |
| // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode. | |
| // | |
| if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) { | |
| continue; | |
| } | |
| if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) { | |
| // | |
| // EDID exist, check whether this mode match with any mode in EDID | |
| // | |
| Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution; | |
| Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution; | |
| if (SearchEdidTiming (&ValidEdidTiming, &Timing) == FALSE) { | |
| continue; | |
| } | |
| } | |
| // | |
| // Select a reasonable mode to be set for current display mode | |
| // | |
| ModeFound = FALSE; | |
| if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 && | |
| BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768 | |
| ) { | |
| ModeFound = TRUE; | |
| } | |
| if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 && | |
| BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600 | |
| ) { | |
| ModeFound = TRUE; | |
| PreferMode = ModeNumber; | |
| } | |
| if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 && | |
| BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480 | |
| ) { | |
| ModeFound = TRUE; | |
| } | |
| if ((!EdidFound) && (!ModeFound)) { | |
| // | |
| // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480 | |
| // | |
| continue; | |
| } | |
| // | |
| // Add mode to the list of available modes | |
| // | |
| ModeNumber ++; | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA), | |
| (VOID **) &ModeBuffer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| if (ModeNumber > 1) { | |
| gBS->CopyMem ( | |
| ModeBuffer, | |
| BiosVideoPrivate->ModeData, | |
| (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA) | |
| ); | |
| } | |
| if (BiosVideoPrivate->ModeData != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->ModeData); | |
| } | |
| CurrentModeData = &ModeBuffer[ModeNumber - 1]; | |
| CurrentModeData->VbeModeNumber = *ModeNumberPtr; | |
| if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) { | |
| CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine; | |
| CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition; | |
| CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1); | |
| CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition; | |
| CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1); | |
| CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition; | |
| CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1); | |
| CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition; | |
| CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1); | |
| } else { | |
| CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine; | |
| CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition; | |
| CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1); | |
| CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition; | |
| CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1); | |
| CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition; | |
| CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1); | |
| CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition; | |
| CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1); | |
| } | |
| CurrentModeData->PixelFormat = PixelBitMask; | |
| if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) && | |
| (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) { | |
| if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) { | |
| CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor; | |
| } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) { | |
| CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; | |
| } | |
| } | |
| CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position; | |
| CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position; | |
| CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position; | |
| CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position; | |
| CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr; | |
| CurrentModeData->FrameBufferSize = BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024; | |
| CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution; | |
| CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution; | |
| CurrentModeData->BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel; | |
| BiosVideoPrivate->ModeData = ModeBuffer; | |
| } | |
| // | |
| // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT | |
| // | |
| if (ModeNumber == 0) { | |
| Status = EFI_DEVICE_ERROR; | |
| goto Done; | |
| } | |
| // | |
| // Allocate buffer for Graphics Output Protocol mode information | |
| // | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), | |
| (VOID **) &BiosVideoPrivate->GraphicsOutput.Mode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| GraphicsOutputMode = BiosVideoPrivate->GraphicsOutput.Mode; | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), | |
| (VOID **) &GraphicsOutputMode->Info | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| GraphicsOutputMode->MaxMode = (UINT32) ModeNumber; | |
| // | |
| // Current mode is unknow till now, set it to an invalid mode. | |
| // | |
| GraphicsOutputMode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER; | |
| // | |
| // Find the best mode to initialize | |
| // | |
| Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode); | |
| if (EFI_ERROR (Status)) { | |
| for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) { | |
| Status = BiosVideoGraphicsOutputSetMode ( | |
| &BiosVideoPrivate->GraphicsOutput, | |
| (UINT32) PreferMode | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| break; | |
| } | |
| } | |
| if (PreferMode == ModeNumber) { | |
| // | |
| // None mode is set successfully. | |
| // | |
| goto Done; | |
| } | |
| } | |
| Done: | |
| // | |
| // If there was an error, then free the mode structure | |
| // | |
| if (EFI_ERROR (Status)) { | |
| if (BiosVideoPrivate->ModeData != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->ModeData); | |
| } | |
| if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) { | |
| if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info); | |
| } | |
| gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Check for VGA device | |
| @param BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure | |
| @retval EFI_SUCCESS Standard VGA device found | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoCheckForVga ( | |
| IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| BIOS_VIDEO_MODE_DATA *ModeBuffer; | |
| // | |
| // Fill in the Graphics Output Protocol | |
| // | |
| BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode; | |
| BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode; | |
| BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVgaBlt; | |
| // | |
| // Allocate buffer for Graphics Output Protocol mode information | |
| // | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), | |
| (VOID **) &BiosVideoPrivate->GraphicsOutput.Mode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), | |
| (VOID **) &BiosVideoPrivate->GraphicsOutput.Mode->Info | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Add mode to the list of available modes | |
| // | |
| BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1; | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (BIOS_VIDEO_MODE_DATA), | |
| (VOID **) &ModeBuffer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| ModeBuffer->VbeModeNumber = 0x0012; | |
| ModeBuffer->BytesPerScanLine = 640; | |
| ModeBuffer->LinearFrameBuffer = (VOID *) (UINTN) (0xa0000); | |
| ModeBuffer->FrameBufferSize = 0; | |
| ModeBuffer->HorizontalResolution = 640; | |
| ModeBuffer->VerticalResolution = 480; | |
| ModeBuffer->BitsPerPixel = 8; | |
| ModeBuffer->PixelFormat = PixelBltOnly; | |
| BiosVideoPrivate->ModeData = ModeBuffer; | |
| // | |
| // Test to see if the Video Adapter support the 640x480 16 color mode | |
| // | |
| BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER; | |
| Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0); | |
| Done: | |
| // | |
| // If there was an error, then free the mode structure | |
| // | |
| if (EFI_ERROR (Status)) { | |
| if (BiosVideoPrivate->ModeData != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->ModeData); | |
| } | |
| if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) { | |
| if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) { | |
| gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info); | |
| } | |
| gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode); | |
| } | |
| } | |
| return Status; | |
| } | |
| // | |
| // Graphics Output Protocol Member Functions for VESA BIOS Extensions | |
| // | |
| /** | |
| Graphics Output protocol interface to get video mode | |
| @param This - Protocol instance pointer. | |
| @param ModeNumber - The mode number to return information on. | |
| @param SizeOfInfo - A pointer to the size, in bytes, of the Info buffer. | |
| @param Info - Caller allocated buffer that returns information about ModeNumber. | |
| @return EFI_SUCCESS - Mode information returned. | |
| EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode. | |
| EFI_NOT_STARTED - Video display is not initialized. Call SetMode () | |
| EFI_INVALID_PARAMETER - One of the input args was NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoGraphicsOutputQueryMode ( | |
| IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, | |
| IN UINT32 ModeNumber, | |
| OUT UINTN *SizeOfInfo, | |
| OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info | |
| ) | |
| { | |
| BIOS_VIDEO_DEV *BiosVideoPrivate; | |
| EFI_STATUS Status; | |
| BIOS_VIDEO_MODE_DATA *ModeData; | |
| BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); | |
| if (BiosVideoPrivate->HardwareNeedsStarting) { | |
| return EFI_NOT_STARTED; | |
| } | |
| if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), | |
| (VOID**) Info | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); | |
| ModeData = &BiosVideoPrivate->ModeData[ModeNumber]; | |
| (*Info)->Version = 0; | |
| (*Info)->HorizontalResolution = ModeData->HorizontalResolution; | |
| (*Info)->VerticalResolution = ModeData->VerticalResolution; | |
| (*Info)->PixelFormat = ModeData->PixelFormat; | |
| (*Info)->PixelInformation = ModeData->PixelBitMask; | |
| (*Info)->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Graphics Output protocol interface to set video mode | |
| @param This - Protocol instance pointer. | |
| @param ModeNumber - The mode number to be set. | |
| @return EFI_SUCCESS - Graphics mode was changed. | |
| EFI_DEVICE_ERROR - The device had an error and could not complete the request. | |
| EFI_UNSUPPORTED - ModeNumber is not supported by this device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoGraphicsOutputSetMode ( | |
| IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, | |
| IN UINT32 ModeNumber | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| BIOS_VIDEO_DEV *BiosVideoPrivate; | |
| IA32_REGISTER_SET Regs; | |
| BIOS_VIDEO_MODE_DATA *ModeData; | |
| BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); | |
| if (This == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (ModeNumber >= This->Mode->MaxMode) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| ModeData = &BiosVideoPrivate->ModeData[ModeNumber]; | |
| if (BiosVideoPrivate->LineBuffer) { | |
| gBS->FreePool (BiosVideoPrivate->LineBuffer); | |
| } | |
| if (BiosVideoPrivate->VgaFrameBuffer) { | |
| gBS->FreePool (BiosVideoPrivate->VgaFrameBuffer); | |
| } | |
| if (BiosVideoPrivate->VbeFrameBuffer) { | |
| gBS->FreePool (BiosVideoPrivate->VbeFrameBuffer); | |
| } | |
| BiosVideoPrivate->LineBuffer = NULL; | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| ModeData->BytesPerScanLine, | |
| (VOID**) &BiosVideoPrivate->LineBuffer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Clear all registers | |
| // | |
| gBS->SetMem (&Regs, sizeof (Regs), 0); | |
| if (ModeData->VbeModeNumber < 0x100) { | |
| // | |
| // Allocate a working buffer for BLT operations to the VGA frame buffer | |
| // | |
| BiosVideoPrivate->VgaFrameBuffer = NULL; | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| 4 * 480 * 80, | |
| (VOID**) &BiosVideoPrivate->VgaFrameBuffer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Set VGA Mode | |
| // | |
| Regs.X.AX = ModeData->VbeModeNumber; | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| } else { | |
| // | |
| // Allocate a working buffer for BLT operations to the VBE frame buffer | |
| // | |
| BiosVideoPrivate->VbeFrameBuffer = NULL; | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| ModeData->BytesPerScanLine * ModeData->VerticalResolution, | |
| (VOID**) &BiosVideoPrivate->VbeFrameBuffer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Set VBE mode | |
| // | |
| Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE; | |
| Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER); | |
| gBS->SetMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK), 0); | |
| Regs.E.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock); | |
| Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock); | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| // | |
| // Check to see if the call succeeded | |
| // | |
| if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| // | |
| // Initialize the state of the VbeFrameBuffer | |
| // | |
| Status = BiosVideoPrivate->PciIo->Mem.Read ( | |
| BiosVideoPrivate->PciIo, | |
| EfiPciIoWidthUint32, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) (UINTN) ModeData->LinearFrameBuffer, | |
| (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2, | |
| BiosVideoPrivate->VbeFrameBuffer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| This->Mode->Mode = ModeNumber; | |
| This->Mode->Info->Version = 0; | |
| This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution; | |
| This->Mode->Info->VerticalResolution = ModeData->VerticalResolution; | |
| This->Mode->Info->PixelFormat = ModeData->PixelFormat; | |
| This->Mode->Info->PixelInformation = ModeData->PixelBitMask; | |
| This->Mode->Info->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel; | |
| This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); | |
| // | |
| // Frame BufferSize remain unchanged | |
| // | |
| This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ModeData->LinearFrameBuffer; | |
| This->Mode->FrameBufferSize = ModeData->FrameBufferSize; | |
| BiosVideoPrivate->HardwareNeedsStarting = FALSE; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Update physical frame buffer, copy 4 bytes block, then copy remaining bytes. | |
| @param PciIo - The pointer of EFI_PCI_IO_PROTOCOL | |
| @param VbeBuffer - The data to transfer to screen | |
| @param MemAddress - Physical frame buffer base address | |
| @param DestinationX - The X coordinate of the destination for BltOperation | |
| @param DestinationY - The Y coordinate of the destination for BltOperation | |
| @param TotalBytes - The total bytes of copy | |
| @param VbePixelWidth - Bytes per pixel | |
| @param BytesPerScanLine - Bytes per scan line | |
| @return None. | |
| **/ | |
| VOID | |
| CopyVideoBuffer ( | |
| IN EFI_PCI_IO_PROTOCOL *PciIo, | |
| IN UINT8 *VbeBuffer, | |
| IN VOID *MemAddress, | |
| IN UINTN DestinationX, | |
| IN UINTN DestinationY, | |
| IN UINTN TotalBytes, | |
| IN UINT32 VbePixelWidth, | |
| IN UINTN BytesPerScanLine | |
| ) | |
| { | |
| UINTN FrameBufferAddr; | |
| UINTN CopyBlockNum; | |
| UINTN RemainingBytes; | |
| UINTN UnalignedBytes; | |
| EFI_STATUS Status; | |
| FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth; | |
| // | |
| // If TotalBytes is less than 4 bytes, only start byte copy. | |
| // | |
| if (TotalBytes < 4) { | |
| Status = PciIo->Mem.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) FrameBufferAddr, | |
| TotalBytes, | |
| VbeBuffer | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return; | |
| } | |
| // | |
| // If VbeBuffer is not 4-byte aligned, start byte copy. | |
| // | |
| UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3; | |
| if (UnalignedBytes != 0) { | |
| Status = PciIo->Mem.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) FrameBufferAddr, | |
| UnalignedBytes, | |
| VbeBuffer | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| FrameBufferAddr += UnalignedBytes; | |
| VbeBuffer += UnalignedBytes; | |
| } | |
| // | |
| // Calculate 4-byte block count and remaining bytes. | |
| // | |
| CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2; | |
| RemainingBytes = (TotalBytes - UnalignedBytes) & 3; | |
| // | |
| // Copy 4-byte block and remaining bytes to physical frame buffer. | |
| // | |
| if (CopyBlockNum != 0) { | |
| Status = PciIo->Mem.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) FrameBufferAddr, | |
| CopyBlockNum, | |
| VbeBuffer | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| if (RemainingBytes != 0) { | |
| FrameBufferAddr += (CopyBlockNum << 2); | |
| VbeBuffer += (CopyBlockNum << 2); | |
| Status = PciIo->Mem.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) FrameBufferAddr, | |
| RemainingBytes, | |
| VbeBuffer | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| } | |
| // | |
| // BUGBUG : Add Blt for 16 bit color, 15 bit color, and 8 bit color modes | |
| // | |
| /** | |
| Graphics Output protocol instance to block transfer for VBE device | |
| @param This - Pointer to Graphics Output protocol instance | |
| @param BltBuffer - The data to transfer to screen | |
| @param BltOperation - The operation to perform | |
| @param SourceX - The X coordinate of the source for BltOperation | |
| @param SourceY - The Y coordinate of the source for BltOperation | |
| @param DestinationX - The X coordinate of the destination for BltOperation | |
| @param DestinationY - The Y coordinate of the destination for BltOperation | |
| @param Width - The width of a rectangle in the blt rectangle in pixels | |
| @param Height - The height of a rectangle in the blt rectangle in pixels | |
| @param Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation. | |
| If a Delta of 0 is used, the entire BltBuffer will be operated on. | |
| If a subrectangle of the BltBuffer is used, then Delta represents | |
| the number of bytes in a row of the BltBuffer. | |
| @return EFI_INVALID_PARAMETER - Invalid parameter passed in | |
| EFI_SUCCESS - Blt operation success | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoGraphicsOutputVbeBlt ( | |
| IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, | |
| IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL | |
| IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, | |
| IN UINTN SourceX, | |
| IN UINTN SourceY, | |
| IN UINTN DestinationX, | |
| IN UINTN DestinationY, | |
| IN UINTN Width, | |
| IN UINTN Height, | |
| IN UINTN Delta | |
| ) | |
| { | |
| BIOS_VIDEO_DEV *BiosVideoPrivate; | |
| BIOS_VIDEO_MODE_DATA *Mode; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| EFI_TPL OriginalTPL; | |
| UINTN DstY; | |
| UINTN SrcY; | |
| UINTN DstX; | |
| EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; | |
| VOID *MemAddress; | |
| EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer; | |
| UINTN BytesPerScanLine; | |
| UINTN Index; | |
| UINT8 *VbeBuffer; | |
| UINT8 *VbeBuffer1; | |
| UINT8 *BltUint8; | |
| UINT32 VbePixelWidth; | |
| UINT32 Pixel; | |
| UINTN TotalBytes; | |
| BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); | |
| Mode = &BiosVideoPrivate->ModeData[This->Mode->Mode]; | |
| PciIo = BiosVideoPrivate->PciIo; | |
| VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer; | |
| MemAddress = Mode->LinearFrameBuffer; | |
| BytesPerScanLine = Mode->BytesPerScanLine; | |
| VbePixelWidth = Mode->BitsPerPixel / 8; | |
| BltUint8 = (UINT8 *) BltBuffer; | |
| TotalBytes = Width * VbePixelWidth; | |
| if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Width == 0 || Height == 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // We need to fill the Virtual Screen buffer with the blt data. | |
| // The virtual screen is upside down, as the first row is the bootom row of | |
| // the image. | |
| // | |
| if (BltOperation == EfiBltVideoToBltBuffer) { | |
| // | |
| // Video to BltBuffer: Source is Video, destination is BltBuffer | |
| // | |
| if (SourceY + Height > Mode->VerticalResolution) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (SourceX + Width > Mode->HorizontalResolution) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } else { | |
| // | |
| // BltBuffer to Video: Source is BltBuffer, destination is Video | |
| // | |
| if (DestinationY + Height > Mode->VerticalResolution) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (DestinationX + Width > Mode->HorizontalResolution) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| // | |
| // If Delta is zero, then the entire BltBuffer is being used, so Delta | |
| // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, | |
| // the number of bytes in each row can be computed. | |
| // | |
| if (Delta == 0) { | |
| Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); | |
| } | |
| // | |
| // We have to raise to TPL Notify, so we make an atomic write the frame buffer. | |
| // We would not want a timer based event (Cursor, ...) to come in while we are | |
| // doing this operation. | |
| // | |
| OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); | |
| switch (BltOperation) { | |
| case EfiBltVideoToBltBuffer: | |
| for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) { | |
| Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); | |
| // | |
| // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL | |
| // | |
| VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth)); | |
| for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) { | |
| Pixel = *(UINT32 *) (VbeBuffer); | |
| Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask); | |
| Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask); | |
| Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask); | |
| Blt->Reserved = 0; | |
| Blt++; | |
| VbeBuffer += VbePixelWidth; | |
| } | |
| } | |
| break; | |
| case EfiBltVideoToVideo: | |
| for (Index = 0; Index < Height; Index++) { | |
| if (DestinationY <= SourceY) { | |
| SrcY = SourceY + Index; | |
| DstY = DestinationY + Index; | |
| } else { | |
| SrcY = SourceY + Height - Index - 1; | |
| DstY = DestinationY + Height - Index - 1; | |
| } | |
| VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth); | |
| VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth); | |
| gBS->CopyMem ( | |
| VbeBuffer, | |
| VbeBuffer1, | |
| TotalBytes | |
| ); | |
| // | |
| // Update physical frame buffer. | |
| // | |
| CopyVideoBuffer ( | |
| PciIo, | |
| VbeBuffer, | |
| MemAddress, | |
| DestinationX, | |
| DstY, | |
| TotalBytes, | |
| VbePixelWidth, | |
| BytesPerScanLine | |
| ); | |
| } | |
| break; | |
| case EfiBltVideoFill: | |
| VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth); | |
| Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8; | |
| // | |
| // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer | |
| // | |
| Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) | | |
| ( | |
| (Blt->Green & Mode->Green.Mask) << | |
| Mode->Green.Position | |
| ) | | |
| ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position); | |
| for (Index = 0; Index < Width; Index++) { | |
| gBS->CopyMem ( | |
| VbeBuffer, | |
| &Pixel, | |
| VbePixelWidth | |
| ); | |
| VbeBuffer += VbePixelWidth; | |
| } | |
| VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth); | |
| for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) { | |
| gBS->CopyMem ( | |
| (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth), | |
| VbeBuffer, | |
| TotalBytes | |
| ); | |
| } | |
| for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) { | |
| // | |
| // Update physical frame buffer. | |
| // | |
| CopyVideoBuffer ( | |
| PciIo, | |
| VbeBuffer, | |
| MemAddress, | |
| DestinationX, | |
| DstY, | |
| TotalBytes, | |
| VbePixelWidth, | |
| BytesPerScanLine | |
| ); | |
| } | |
| break; | |
| case EfiBltBufferToVideo: | |
| for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) { | |
| Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); | |
| VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth)); | |
| for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) { | |
| // | |
| // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer | |
| // | |
| Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) | | |
| ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) | | |
| ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position); | |
| gBS->CopyMem ( | |
| VbeBuffer, | |
| &Pixel, | |
| VbePixelWidth | |
| ); | |
| Blt++; | |
| VbeBuffer += VbePixelWidth; | |
| } | |
| VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth)); | |
| // | |
| // Update physical frame buffer. | |
| // | |
| CopyVideoBuffer ( | |
| PciIo, | |
| VbeBuffer, | |
| MemAddress, | |
| DestinationX, | |
| DstY, | |
| TotalBytes, | |
| VbePixelWidth, | |
| BytesPerScanLine | |
| ); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| gBS->RestoreTPL (OriginalTPL); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Write graphics controller registers | |
| @param PciIo - Pointer to PciIo protocol instance of the controller | |
| @param Address - Register address | |
| @param Data - Data to be written to register | |
| @return None | |
| **/ | |
| STATIC | |
| VOID | |
| WriteGraphicsController ( | |
| IN EFI_PCI_IO_PROTOCOL *PciIo, | |
| IN UINTN Address, | |
| IN UINTN Data | |
| ) | |
| { | |
| Address = Address | (Data << 8); | |
| PciIo->Io.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint16, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER, | |
| 1, | |
| &Address | |
| ); | |
| } | |
| /** | |
| Read the four bit plane of VGA frame buffer | |
| @param PciIo - Pointer to PciIo protocol instance of the controller | |
| @param HardwareBuffer - Hardware VGA frame buffer address | |
| @param MemoryBuffer - Memory buffer address | |
| @param WidthInBytes - Number of bytes in a line to read | |
| @param Height - Height of the area to read | |
| @return None | |
| **/ | |
| VOID | |
| VgaReadBitPlanes ( | |
| EFI_PCI_IO_PROTOCOL *PciIo, | |
| UINT8 *HardwareBuffer, | |
| UINT8 *MemoryBuffer, | |
| UINTN WidthInBytes, | |
| UINTN Height | |
| ) | |
| { | |
| UINTN BitPlane; | |
| UINTN Rows; | |
| UINTN FrameBufferOffset; | |
| UINT8 *Source; | |
| UINT8 *Destination; | |
| // | |
| // Program the Mode Register Write mode 0, Read mode 0 | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_MODE_REGISTER, | |
| VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0 | |
| ); | |
| for (BitPlane = 0, FrameBufferOffset = 0; | |
| BitPlane < VGA_NUMBER_OF_BIT_PLANES; | |
| BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE | |
| ) { | |
| // | |
| // Program the Read Map Select Register to select the correct bit plane | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER, | |
| BitPlane | |
| ); | |
| Source = HardwareBuffer; | |
| Destination = MemoryBuffer + FrameBufferOffset; | |
| for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) { | |
| PciIo->Mem.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| (UINT8) EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64)(UINTN) Source, | |
| WidthInBytes, | |
| (VOID *) Destination | |
| ); | |
| } | |
| } | |
| } | |
| /** | |
| Internal routine to convert VGA color to Grahpics Output color | |
| @param MemoryBuffer - Buffer containing VGA color | |
| @param X - The X coordinate of pixel on screen | |
| @param Y - The Y coordinate of pixel on screen | |
| @param BltBuffer - Buffer to contain converted Grahpics Output color | |
| @return None | |
| **/ | |
| VOID | |
| VgaConvertToGraphicsOutputColor ( | |
| UINT8 *MemoryBuffer, | |
| UINTN X, | |
| UINTN Y, | |
| EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer | |
| ) | |
| { | |
| UINTN Mask; | |
| UINTN Bit; | |
| UINTN Color; | |
| MemoryBuffer += ((Y << 6) + (Y << 4) + (X >> 3)); | |
| Mask = mVgaBitMaskTable[X & 0x07]; | |
| for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) { | |
| if (*MemoryBuffer & Mask) { | |
| Color |= Bit; | |
| } | |
| } | |
| *BltBuffer = mVgaColorToGraphicsOutputColor[Color]; | |
| } | |
| /** | |
| Internal routine to convert Grahpics Output color to VGA color | |
| @param BltBuffer - buffer containing Grahpics Output color | |
| @return Converted VGA color | |
| **/ | |
| UINT8 | |
| VgaConvertColor ( | |
| IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer | |
| ) | |
| { | |
| UINT8 Color; | |
| Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04)); | |
| if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) { | |
| Color |= 0x08; | |
| } | |
| return Color; | |
| } | |
| /** | |
| Grahpics Output protocol instance to block transfer for VGA device | |
| @param This Pointer to Grahpics Output protocol instance | |
| @param BltBuffer The data to transfer to screen | |
| @param BltOperation The operation to perform | |
| @param SourceX The X coordinate of the source for BltOperation | |
| @param SourceY The Y coordinate of the source for BltOperation | |
| @param DestinationX The X coordinate of the destination for BltOperation | |
| @param DestinationY The Y coordinate of the destination for BltOperation | |
| @param Width The width of a rectangle in the blt rectangle in pixels | |
| @param Height The height of a rectangle in the blt rectangle in pixels | |
| @param Delta Not used for EfiBltVideoFill and EfiBltVideoToVideo operation. | |
| If a Delta of 0 is used, the entire BltBuffer will be operated on. | |
| If a subrectangle of the BltBuffer is used, then Delta represents | |
| the number of bytes in a row of the BltBuffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter passed in | |
| @retval EFI_SUCCESS Blt operation success | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoGraphicsOutputVgaBlt ( | |
| IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, | |
| IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL | |
| IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, | |
| IN UINTN SourceX, | |
| IN UINTN SourceY, | |
| IN UINTN DestinationX, | |
| IN UINTN DestinationY, | |
| IN UINTN Width, | |
| IN UINTN Height, | |
| IN UINTN Delta | |
| ) | |
| { | |
| BIOS_VIDEO_DEV *BiosVideoPrivate; | |
| EFI_TPL OriginalTPL; | |
| UINT8 *MemAddress; | |
| UINTN BytesPerScanLine; | |
| //UINTN BytesPerBitPlane; | |
| UINTN Bit; | |
| UINTN Index; | |
| UINTN Index1; | |
| UINTN StartAddress; | |
| UINTN Bytes; | |
| UINTN Offset; | |
| UINT8 LeftMask; | |
| UINT8 RightMask; | |
| UINTN Address; | |
| UINTN AddressFix; | |
| UINT8 *Address1; | |
| UINT8 *SourceAddress; | |
| UINT8 *DestinationAddress; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| UINT8 Data; | |
| UINT8 PixelColor; | |
| UINT8 *VgaFrameBuffer; | |
| UINTN SourceOffset; | |
| UINTN SourceWidth; | |
| UINTN Rows; | |
| UINTN Columns; | |
| UINTN X; | |
| UINTN Y; | |
| UINTN CurrentMode; | |
| BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); | |
| CurrentMode = This->Mode->Mode; | |
| PciIo = BiosVideoPrivate->PciIo; | |
| MemAddress = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer; | |
| BytesPerScanLine = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3; | |
| //BytesPerBitPlane = BytesPerScanLine * BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution; | |
| VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer; | |
| if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Width == 0 || Height == 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // We need to fill the Virtual Screen buffer with the blt data. | |
| // The virtual screen is upside down, as the first row is the bootom row of | |
| // the image. | |
| // | |
| if (BltOperation == EfiBltVideoToBltBuffer) { | |
| // | |
| // Video to BltBuffer: Source is Video, destination is BltBuffer | |
| // | |
| if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } else { | |
| // | |
| // BltBuffer to Video: Source is BltBuffer, destination is Video | |
| // | |
| if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| // | |
| // If Delta is zero, then the entire BltBuffer is being used, so Delta | |
| // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, | |
| // the number of bytes in each row can be computed. | |
| // | |
| if (Delta == 0) { | |
| Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); | |
| } | |
| // | |
| // We have to raise to TPL Notify, so we make an atomic write the frame buffer. | |
| // We would not want a timer based event (Cursor, ...) to come in while we are | |
| // doing this operation. | |
| // | |
| OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); | |
| // | |
| // Compute some values we need for VGA | |
| // | |
| switch (BltOperation) { | |
| case EfiBltVideoToBltBuffer: | |
| SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3); | |
| SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1; | |
| // | |
| // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer | |
| // | |
| VgaReadBitPlanes ( | |
| PciIo, | |
| MemAddress + SourceOffset, | |
| VgaFrameBuffer + SourceOffset, | |
| SourceWidth, | |
| Height | |
| ); | |
| // | |
| // Convert VGA Bit Planes to a Graphics Output 32-bit color value | |
| // | |
| BltBuffer += (DestinationY * (Delta >> 2) + DestinationX); | |
| for (Rows = 0, Y = SourceY; Rows < Height; Rows++, Y++, BltBuffer += (Delta >> 2)) { | |
| for (Columns = 0, X = SourceX; Columns < Width; Columns++, X++, BltBuffer++) { | |
| VgaConvertToGraphicsOutputColor (VgaFrameBuffer, X, Y, BltBuffer); | |
| } | |
| BltBuffer -= Width; | |
| } | |
| break; | |
| case EfiBltVideoToVideo: | |
| // | |
| // Check for an aligned Video to Video operation | |
| // | |
| if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) { | |
| // | |
| // Program the Mode Register Write mode 1, Read mode 0 | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_MODE_REGISTER, | |
| VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1 | |
| ); | |
| SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3)); | |
| DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3)); | |
| Bytes = Width >> 3; | |
| for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) { | |
| PciIo->CopyMem ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) ((UINTN)DestinationAddress + Offset), | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) ((UINTN)SourceAddress + Offset), | |
| Bytes | |
| ); | |
| } | |
| } else { | |
| SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3); | |
| SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1; | |
| // | |
| // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer | |
| // | |
| VgaReadBitPlanes ( | |
| PciIo, | |
| MemAddress + SourceOffset, | |
| VgaFrameBuffer + SourceOffset, | |
| SourceWidth, | |
| Height | |
| ); | |
| } | |
| break; | |
| case EfiBltVideoFill: | |
| StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3)); | |
| Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3); | |
| LeftMask = mVgaLeftMaskTable[DestinationX & 0x07]; | |
| RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07]; | |
| if (Bytes == 0) { | |
| LeftMask = (UINT8) (LeftMask & RightMask); | |
| RightMask = 0; | |
| } | |
| if (LeftMask == 0xff) { | |
| StartAddress--; | |
| Bytes++; | |
| LeftMask = 0; | |
| } | |
| if (RightMask == 0xff) { | |
| Bytes++; | |
| RightMask = 0; | |
| } | |
| PixelColor = VgaConvertColor (BltBuffer); | |
| // | |
| // Program the Mode Register Write mode 2, Read mode 0 | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_MODE_REGISTER, | |
| VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2 | |
| ); | |
| // | |
| // Program the Data Rotate/Function Select Register to replace | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER, | |
| VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE | |
| ); | |
| if (LeftMask != 0) { | |
| // | |
| // Program the BitMask register with the Left column mask | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER, | |
| LeftMask | |
| ); | |
| for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) { | |
| // | |
| // Read data from the bit planes into the latches | |
| // | |
| PciIo->Mem.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) Address, | |
| 1, | |
| &Data | |
| ); | |
| // | |
| // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask | |
| // | |
| PciIo->Mem.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) Address, | |
| 1, | |
| &PixelColor | |
| ); | |
| } | |
| } | |
| if (Bytes > 1) { | |
| // | |
| // Program the BitMask register with the middle column mask of 0xff | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER, | |
| 0xff | |
| ); | |
| for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) { | |
| PciIo->Mem.Write ( | |
| PciIo, | |
| EfiPciIoWidthFillUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) Address, | |
| Bytes - 1, | |
| &PixelColor | |
| ); | |
| } | |
| } | |
| if (RightMask != 0) { | |
| // | |
| // Program the BitMask register with the Right column mask | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER, | |
| RightMask | |
| ); | |
| for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) { | |
| // | |
| // Read data from the bit planes into the latches | |
| // | |
| PciIo->Mem.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) Address, | |
| 1, | |
| &Data | |
| ); | |
| // | |
| // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask | |
| // | |
| PciIo->Mem.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64) Address, | |
| 1, | |
| &PixelColor | |
| ); | |
| } | |
| } | |
| break; | |
| case EfiBltBufferToVideo: | |
| StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3)); | |
| LeftMask = mVgaBitMaskTable[DestinationX & 0x07]; | |
| // | |
| // Program the Mode Register Write mode 2, Read mode 0 | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_MODE_REGISTER, | |
| VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2 | |
| ); | |
| // | |
| // Program the Data Rotate/Function Select Register to replace | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER, | |
| VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE | |
| ); | |
| for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) { | |
| for (Index1 = 0; Index1 < Width; Index1++) { | |
| BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]); | |
| } | |
| AddressFix = Address; | |
| for (Bit = 0; Bit < 8; Bit++) { | |
| // | |
| // Program the BitMask register with the Left column mask | |
| // | |
| WriteGraphicsController ( | |
| PciIo, | |
| VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER, | |
| LeftMask | |
| ); | |
| for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) { | |
| // | |
| // Read data from the bit planes into the latches | |
| // | |
| PciIo->Mem.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64)(UINTN) Address1, | |
| 1, | |
| &Data | |
| ); | |
| PciIo->Mem.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint8, | |
| EFI_PCI_IO_PASS_THROUGH_BAR, | |
| (UINT64)(UINTN) Address1, | |
| 1, | |
| &BiosVideoPrivate->LineBuffer[Index1] | |
| ); | |
| } | |
| LeftMask = (UINT8) (LeftMask >> 1); | |
| if (LeftMask == 0) { | |
| LeftMask = 0x80; | |
| AddressFix++; | |
| } | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| gBS->RestoreTPL (OriginalTPL); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // VGA Mini Port Protocol Functions | |
| // | |
| /** | |
| VgaMiniPort protocol interface to set mode | |
| @param This Pointer to VgaMiniPort protocol instance | |
| @param ModeNumber The index of the mode | |
| @retval EFI_UNSUPPORTED The requested mode is not supported | |
| @retval EFI_SUCCESS The requested mode is set successfully | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosVideoVgaMiniPortSetMode ( | |
| IN EFI_VGA_MINI_PORT_PROTOCOL *This, | |
| IN UINTN ModeNumber | |
| ) | |
| { | |
| BIOS_VIDEO_DEV *BiosVideoPrivate; | |
| IA32_REGISTER_SET Regs; | |
| if (This == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Make sure the ModeNumber is a valid value | |
| // | |
| if (ModeNumber >= This->MaxMode) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Get the device structure for this device | |
| // | |
| BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This); | |
| gBS->SetMem (&Regs, sizeof (Regs), 0); | |
| switch (ModeNumber) { | |
| case 0: | |
| // | |
| // Set the 80x25 Text VGA Mode | |
| // | |
| Regs.H.AH = 0x00; | |
| Regs.H.AL = 0x83; | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| Regs.H.AH = 0x11; | |
| Regs.H.AL = 0x14; | |
| Regs.H.BL = 0; | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| break; | |
| case 1: | |
| // | |
| // Set the 80x50 Text VGA Mode | |
| // | |
| Regs.H.AH = 0x00; | |
| Regs.H.AL = 0x83; | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| Regs.H.AH = 0x11; | |
| Regs.H.AL = 0x12; | |
| Regs.H.BL = 0; | |
| LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); | |
| break; | |
| default: | |
| return EFI_UNSUPPORTED; | |
| } | |
| return EFI_SUCCESS; | |
| } |