mirror of https://github.com/acidanthera/audk.git
1528 lines
47 KiB
C
1528 lines
47 KiB
C
/** @file
|
|
ConsoleOut Routines that speak VGA.
|
|
|
|
Copyright (c) 2007 - 2013, 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 "FbGop.h"
|
|
|
|
EFI_PIXEL_BITMASK mPixelBitMask = {0x0000FF, 0x00FF00, 0xFF0000, 0x000000};
|
|
|
|
//
|
|
// Save controller attributes during first start
|
|
//
|
|
UINT64 mOriginalPciAttributes;
|
|
BOOLEAN mPciAttributesSaved = FALSE;
|
|
|
|
|
|
//
|
|
// EFI Driver Binding Protocol Instance
|
|
//
|
|
EFI_DRIVER_BINDING_PROTOCOL gFbGopDriverBinding = {
|
|
FbGopDriverBindingSupported,
|
|
FbGopDriverBindingStart,
|
|
FbGopDriverBindingStop,
|
|
0x3,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
//
|
|
// Native resolution in EDID DetailedTiming[0]
|
|
//
|
|
UINT32 mNativeModeHorizontal;
|
|
UINT32 mNativeModeVertical;
|
|
|
|
/**
|
|
Supported.
|
|
|
|
@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_STATUS EFI_SUCCESS:This controller can be managed by this
|
|
driver, Otherwise, this controller cannot be
|
|
managed by this driver
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FbGopDriverBindingSupported (
|
|
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;
|
|
EFI_DEV_PATH *Node;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// See if this is a PCI Graphics Controller by looking at the Command register and
|
|
// Class Code Register
|
|
//
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0,
|
|
sizeof (Pci) / sizeof (UINT32),
|
|
&Pci
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Done;
|
|
}
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
if (Pci.Hdr.ClassCode[2] == 0x03 || (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01)) {
|
|
|
|
Status = EFI_SUCCESS;
|
|
//
|
|
// If this is a graphics controller,
|
|
// go further check RemainingDevicePath validation
|
|
//
|
|
if (RemainingDevicePath != NULL) {
|
|
Node = (EFI_DEV_PATH *) RemainingDevicePath;
|
|
//
|
|
// Check if RemainingDevicePath is the End of Device Path Node,
|
|
// if yes, return EFI_SUCCESS
|
|
//
|
|
if (!IsDevicePathEnd (Node)) {
|
|
//
|
|
// If RemainingDevicePath isn't the End of Device Path Node,
|
|
// check its validation
|
|
//
|
|
if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
|
|
Node->DevPath.SubType != ACPI_ADR_DP ||
|
|
DevicePathNodeLength(&Node->DevPath) < sizeof(ACPI_ADR_DEVICE_PATH)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
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
|
|
FbGopDriverBindingStart (
|
|
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;
|
|
UINT64 Supports;
|
|
|
|
DEBUG ((EFI_D_INFO, "GOP START\n"));
|
|
|
|
//
|
|
// Initialize local variables
|
|
//
|
|
PciIo = NULL;
|
|
ParentDevicePath = NULL;
|
|
|
|
//
|
|
// Prepare for status code
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
Controller,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &ParentDevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// 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) && (Status != EFI_ALREADY_STARTED)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Save original PCI attributes
|
|
//
|
|
if (!mPciAttributesSaved) {
|
|
Status = PciIo->Attributes (
|
|
PciIo,
|
|
EfiPciIoAttributeOperationGet,
|
|
0,
|
|
&mOriginalPciAttributes
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
mPciAttributesSaved = TRUE;
|
|
}
|
|
|
|
//
|
|
// Get supported PCI attributes
|
|
//
|
|
Status = PciIo->Attributes (
|
|
PciIo,
|
|
EfiPciIoAttributeOperationSupported,
|
|
0,
|
|
&Supports
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
Supports &= (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
|
|
if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Done;
|
|
}
|
|
|
|
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
|
|
EFI_PROGRESS_CODE,
|
|
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,
|
|
ParentDevicePath
|
|
);
|
|
//
|
|
// Enable the device and make sure VGA cycles are being forwarded to this VGA device
|
|
//
|
|
Status = PciIo->Attributes (
|
|
PciIo,
|
|
EfiPciIoAttributeOperationEnable,
|
|
EFI_PCI_DEVICE_ENABLE,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
|
|
EFI_ERROR_CODE | EFI_ERROR_MINOR,
|
|
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT,
|
|
ParentDevicePath
|
|
);
|
|
goto Done;
|
|
}
|
|
|
|
if (RemainingDevicePath != NULL) {
|
|
if (IsDevicePathEnd (RemainingDevicePath)) {
|
|
//
|
|
// If RemainingDevicePath is the End of Device Path Node,
|
|
// don't create any child device and return EFI_SUCESS
|
|
Status = EFI_SUCCESS;
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create child handle and install GraphicsOutputProtocol on it
|
|
//
|
|
Status = FbGopChildHandleInstall (
|
|
This,
|
|
Controller,
|
|
PciIo,
|
|
NULL,
|
|
ParentDevicePath,
|
|
RemainingDevicePath
|
|
);
|
|
|
|
Done:
|
|
if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
|
|
|
|
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
|
|
EFI_PROGRESS_CODE,
|
|
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,
|
|
ParentDevicePath
|
|
);
|
|
|
|
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
|
|
EFI_PROGRESS_CODE,
|
|
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,
|
|
ParentDevicePath
|
|
);
|
|
if (!HasChildHandle (Controller)) {
|
|
if (mPciAttributesSaved) {
|
|
//
|
|
// Restore original PCI attributes
|
|
//
|
|
PciIo->Attributes (
|
|
PciIo,
|
|
EfiPciIoAttributeOperationSet,
|
|
mOriginalPciAttributes,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
//
|
|
// Release PCI I/O Protocols on the controller handle.
|
|
//
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Stop.
|
|
|
|
@param This Pointer to driver binding protocol
|
|
@param Controller Controller handle to connect
|
|
@param NumberOfChildren Number of children handle created by this driver
|
|
@param ChildHandleBuffer Buffer containing child handle created
|
|
|
|
@retval EFI_SUCCESS Driver disconnected successfully from controller
|
|
@retval EFI_UNSUPPORTED Cannot find FB_VIDEO_DEV structure
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FbGopDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN AllChildrenStopped;
|
|
UINTN Index;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
|
|
AllChildrenStopped = TRUE;
|
|
|
|
if (NumberOfChildren == 0) {
|
|
//
|
|
// Close PCI I/O protocol on the controller handle
|
|
//
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
for (Index = 0; Index < NumberOfChildren; Index++) {
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
FbGopChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
AllChildrenStopped = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!AllChildrenStopped) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (!HasChildHandle (Controller)) {
|
|
if (mPciAttributesSaved) {
|
|
Status = gBS->HandleProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &PciIo
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Restore original PCI attributes
|
|
//
|
|
Status = PciIo->Attributes (
|
|
PciIo,
|
|
EfiPciIoAttributeOperationSet,
|
|
mOriginalPciAttributes,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
}
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Install child handles if the Handle supports MBR format.
|
|
|
|
@param This Calling context.
|
|
@param ParentHandle Parent Handle
|
|
@param ParentPciIo Parent PciIo interface
|
|
@param ParentLegacyBios Parent LegacyBios interface
|
|
@param ParentDevicePath Parent Device Path
|
|
@param RemainingDevicePath Remaining Device Path
|
|
|
|
@retval EFI_SUCCESS If a child handle was added
|
|
@retval other A child handle was not added
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FbGopChildHandleInstall (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE ParentHandle,
|
|
IN EFI_PCI_IO_PROTOCOL *ParentPciIo,
|
|
IN VOID *ParentLegacyBios,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
FB_VIDEO_DEV *FbGopPrivate;
|
|
PCI_TYPE00 Pci;
|
|
ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
|
|
|
|
//
|
|
// Allocate the private device structure for video device
|
|
//
|
|
FbGopPrivate = (FB_VIDEO_DEV *) AllocateZeroPool (
|
|
sizeof (FB_VIDEO_DEV)
|
|
);
|
|
if (NULL == FbGopPrivate) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// See if this is a VGA compatible controller or not
|
|
//
|
|
Status = ParentPciIo->Pci.Read (
|
|
ParentPciIo,
|
|
EfiPciIoWidthUint32,
|
|
0,
|
|
sizeof (Pci) / sizeof (UINT32),
|
|
&Pci
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
|
|
EFI_ERROR_CODE | EFI_ERROR_MINOR,
|
|
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
|
|
ParentDevicePath
|
|
);
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Initialize the child private structure
|
|
//
|
|
FbGopPrivate->Signature = FB_VIDEO_DEV_SIGNATURE;
|
|
|
|
//
|
|
// Fill in Graphics Output specific mode structures
|
|
//
|
|
FbGopPrivate->ModeData = NULL;
|
|
|
|
FbGopPrivate->VbeFrameBuffer = NULL;
|
|
|
|
FbGopPrivate->EdidDiscovered.SizeOfEdid = 0;
|
|
FbGopPrivate->EdidDiscovered.Edid = NULL;
|
|
FbGopPrivate->EdidActive.SizeOfEdid = 0;
|
|
FbGopPrivate->EdidActive.Edid = NULL;
|
|
|
|
//
|
|
// Fill in the Graphics Output Protocol
|
|
//
|
|
FbGopPrivate->GraphicsOutput.QueryMode = FbGopGraphicsOutputQueryMode;
|
|
FbGopPrivate->GraphicsOutput.SetMode = FbGopGraphicsOutputSetMode;
|
|
|
|
|
|
//
|
|
// Allocate buffer for Graphics Output Protocol mode information
|
|
//
|
|
FbGopPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool (
|
|
sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)
|
|
);
|
|
if (NULL == FbGopPrivate->GraphicsOutput.Mode) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
|
|
FbGopPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
|
|
sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
|
|
);
|
|
if (NULL == FbGopPrivate->GraphicsOutput.Mode->Info) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.
|
|
//
|
|
if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) {
|
|
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));
|
|
|
|
FbGopPrivate->GopDevicePath = AppendDevicePathNode (
|
|
ParentDevicePath,
|
|
(EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
|
|
);
|
|
} else {
|
|
FbGopPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
|
|
}
|
|
|
|
//
|
|
// Creat child handle and device path protocol firstly
|
|
//
|
|
FbGopPrivate->Handle = NULL;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&FbGopPrivate->Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
FbGopPrivate->GopDevicePath,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
//
|
|
// When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
|
|
//
|
|
FbGopPrivate->PciIo = ParentPciIo;
|
|
|
|
//
|
|
// Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
|
|
//
|
|
Status = FbGopCheckForVbe (FbGopPrivate);
|
|
DEBUG ((EFI_D_INFO, "FbGopCheckForVbe - %r\n", Status));
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
//goto Done;
|
|
}
|
|
|
|
//
|
|
// Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&FbGopPrivate->Handle,
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
&FbGopPrivate->GraphicsOutput,
|
|
&gEfiEdidDiscoveredProtocolGuid,
|
|
&FbGopPrivate->EdidDiscovered,
|
|
&gEfiEdidActiveProtocolGuid,
|
|
&FbGopPrivate->EdidActive,
|
|
NULL
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Open the Parent Handle for the child
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
ParentHandle,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &FbGopPrivate->PciIo,
|
|
This->DriverBindingHandle,
|
|
FbGopPrivate->Handle,
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
Done:
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Free private data structure
|
|
//
|
|
FbGopDeviceReleaseResource (FbGopPrivate);
|
|
}
|
|
|
|
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
|
|
FbGopChildHandleUninstall (
|
|
EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
EFI_HANDLE Controller,
|
|
EFI_HANDLE Handle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
|
|
FB_VIDEO_DEV *FbGopPrivate;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
|
|
FbGopPrivate = NULL;
|
|
GraphicsOutput = NULL;
|
|
PciIo = NULL;
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Handle,
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
(VOID **) &GraphicsOutput,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
|
|
}
|
|
|
|
if (FbGopPrivate == 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
|
|
//
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
FbGopPrivate->Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
FbGopPrivate->GopDevicePath,
|
|
&gEfiGraphicsOutputProtocolGuid,
|
|
&FbGopPrivate->GraphicsOutput,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &PciIo,
|
|
This->DriverBindingHandle,
|
|
Handle,
|
|
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Release all allocated resources
|
|
//
|
|
FbGopDeviceReleaseResource (FbGopPrivate);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Release resource for biso video instance.
|
|
|
|
@param FbGopPrivate Video child device private data structure
|
|
|
|
**/
|
|
VOID
|
|
FbGopDeviceReleaseResource (
|
|
FB_VIDEO_DEV *FbGopPrivate
|
|
)
|
|
{
|
|
if (FbGopPrivate == NULL) {
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Release all the resourses occupied by the FB_VIDEO_DEV
|
|
//
|
|
|
|
//
|
|
// Free VBE Frame Buffer
|
|
//
|
|
if (FbGopPrivate->VbeFrameBuffer != NULL) {
|
|
FreePool (FbGopPrivate->VbeFrameBuffer);
|
|
}
|
|
|
|
//
|
|
// Free mode data
|
|
//
|
|
if (FbGopPrivate->ModeData != NULL) {
|
|
FreePool (FbGopPrivate->ModeData);
|
|
}
|
|
|
|
//
|
|
// Free graphics output protocol occupied resource
|
|
//
|
|
if (FbGopPrivate->GraphicsOutput.Mode != NULL) {
|
|
if (FbGopPrivate->GraphicsOutput.Mode->Info != NULL) {
|
|
FreePool (FbGopPrivate->GraphicsOutput.Mode->Info);
|
|
FbGopPrivate->GraphicsOutput.Mode->Info = NULL;
|
|
}
|
|
FreePool (FbGopPrivate->GraphicsOutput.Mode);
|
|
FbGopPrivate->GraphicsOutput.Mode = NULL;
|
|
}
|
|
|
|
if (FbGopPrivate->GopDevicePath!= NULL) {
|
|
FreePool (FbGopPrivate->GopDevicePath);
|
|
}
|
|
|
|
FreePool (FbGopPrivate);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Check if all video child handles have been uninstalled.
|
|
|
|
@param Controller Video controller handle
|
|
|
|
@return TRUE Child handles exist.
|
|
@return FALSE All video child handles have been uninstalled.
|
|
|
|
**/
|
|
BOOLEAN
|
|
HasChildHandle (
|
|
IN EFI_HANDLE Controller
|
|
)
|
|
{
|
|
UINTN Index;
|
|
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
|
|
UINTN EntryCount;
|
|
BOOLEAN HasChild;
|
|
|
|
EntryCount = 0;
|
|
HasChild = FALSE;
|
|
gBS->OpenProtocolInformation (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
&OpenInfoBuffer,
|
|
&EntryCount
|
|
);
|
|
for (Index = 0; Index < EntryCount; Index++) {
|
|
if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
|
|
HasChild = TRUE;
|
|
}
|
|
}
|
|
|
|
return HasChild;
|
|
}
|
|
|
|
/**
|
|
Check for VBE device.
|
|
|
|
@param FbGopPrivate Pointer to FB_VIDEO_DEV structure
|
|
|
|
@retval EFI_SUCCESS VBE device found
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FbGopCheckForVbe (
|
|
IN OUT FB_VIDEO_DEV *FbGopPrivate
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
FB_VIDEO_MODE_DATA *ModeBuffer;
|
|
FB_VIDEO_MODE_DATA *CurrentModeData;
|
|
UINTN ModeNumber;
|
|
UINTN BitsPerPixel;
|
|
UINTN BytesPerScanLine;
|
|
UINT32 HorizontalResolution;
|
|
UINT32 VerticalResolution;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
|
|
EFI_HOB_GUID_TYPE *GuidHob;
|
|
FRAME_BUFFER_INFO *pFbInfo;
|
|
|
|
Status = EFI_SUCCESS;
|
|
//
|
|
// Find the frame buffer information guid hob
|
|
//
|
|
GuidHob = GetFirstGuidHob (&gUefiFrameBufferInfoGuid);
|
|
ASSERT (GuidHob != NULL);
|
|
pFbInfo = (FRAME_BUFFER_INFO *)GET_GUID_HOB_DATA (GuidHob);
|
|
|
|
//
|
|
// Add mode to the list of available modes
|
|
//
|
|
VbeFrameBuffer = NULL;
|
|
ModeBuffer = NULL;
|
|
|
|
ModeNumber = 1;
|
|
BitsPerPixel = pFbInfo->BitsPerPixel;
|
|
HorizontalResolution = pFbInfo->HorizontalResolution;
|
|
VerticalResolution = pFbInfo->VerticalResolution;
|
|
BytesPerScanLine = HorizontalResolution * (BitsPerPixel / 8);
|
|
|
|
ModeBuffer = (FB_VIDEO_MODE_DATA *) AllocatePool (
|
|
ModeNumber * sizeof (FB_VIDEO_MODE_DATA)
|
|
);
|
|
if (NULL == ModeBuffer) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
|
|
VbeFrameBuffer =
|
|
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (
|
|
BytesPerScanLine * VerticalResolution
|
|
);
|
|
if (NULL == VbeFrameBuffer) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
|
|
if (FbGopPrivate->ModeData != NULL) {
|
|
FreePool (FbGopPrivate->ModeData);
|
|
}
|
|
|
|
if (FbGopPrivate->VbeFrameBuffer != NULL) {
|
|
FreePool (FbGopPrivate->VbeFrameBuffer);
|
|
}
|
|
|
|
CurrentModeData = &ModeBuffer[ModeNumber - 1];
|
|
CurrentModeData->BytesPerScanLine = (UINT16)BytesPerScanLine;
|
|
|
|
CurrentModeData->Red = *(FB_VIDEO_COLOR_PLACEMENT *)&(pFbInfo->Red);
|
|
CurrentModeData->Blue = *(FB_VIDEO_COLOR_PLACEMENT *)&(pFbInfo->Blue);
|
|
CurrentModeData->Green = *(FB_VIDEO_COLOR_PLACEMENT *)&(pFbInfo->Green);
|
|
CurrentModeData->Reserved = *(FB_VIDEO_COLOR_PLACEMENT *)&(pFbInfo->Reserved);
|
|
|
|
CurrentModeData->BitsPerPixel = (UINT32)BitsPerPixel;
|
|
CurrentModeData->HorizontalResolution = HorizontalResolution;
|
|
CurrentModeData->VerticalResolution = VerticalResolution;
|
|
CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;
|
|
CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN) pFbInfo->LinearFrameBuffer;
|
|
CurrentModeData->VbeModeNumber = 0;
|
|
CurrentModeData->ColorDepth = 32;
|
|
CurrentModeData->RefreshRate = 60;
|
|
|
|
CurrentModeData->PixelFormat = PixelBitMask;
|
|
if ((CurrentModeData->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;
|
|
}
|
|
}
|
|
|
|
CopyMem (&(CurrentModeData->PixelBitMask), &mPixelBitMask, sizeof (EFI_PIXEL_BITMASK));
|
|
|
|
FbGopPrivate->ModeData = ModeBuffer;
|
|
FbGopPrivate->VbeFrameBuffer = VbeFrameBuffer;
|
|
|
|
//
|
|
// Assign Gop's Blt function
|
|
//
|
|
FbGopPrivate->GraphicsOutput.Blt = FbGopGraphicsOutputVbeBlt;
|
|
|
|
FbGopPrivate->GraphicsOutput.Mode->MaxMode = 1;
|
|
FbGopPrivate->GraphicsOutput.Mode->Mode = 0;
|
|
FbGopPrivate->GraphicsOutput.Mode->Info->Version = 0;
|
|
FbGopPrivate->GraphicsOutput.Mode->Info->HorizontalResolution = HorizontalResolution;
|
|
FbGopPrivate->GraphicsOutput.Mode->Info->VerticalResolution = VerticalResolution;
|
|
FbGopPrivate->GraphicsOutput.Mode->Info->PixelFormat = CurrentModeData->PixelFormat;
|
|
CopyMem (&(FbGopPrivate->GraphicsOutput.Mode->Info->PixelInformation), &mPixelBitMask, sizeof (EFI_PIXEL_BITMASK));
|
|
FbGopPrivate->GraphicsOutput.Mode->Info->PixelsPerScanLine = HorizontalResolution;
|
|
FbGopPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
|
|
FbGopPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) CurrentModeData->LinearFrameBuffer;
|
|
FbGopPrivate->GraphicsOutput.Mode->FrameBufferSize = CurrentModeData->FrameBufferSize;
|
|
|
|
//
|
|
// Find the best mode to initialize
|
|
//
|
|
|
|
Done:
|
|
//
|
|
// If there was an error, then free the mode structure
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
if (VbeFrameBuffer != NULL) {
|
|
FreePool (VbeFrameBuffer);
|
|
}
|
|
|
|
if (ModeBuffer != NULL) {
|
|
FreePool (ModeBuffer);
|
|
}
|
|
}
|
|
|
|
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.
|
|
|
|
@retval EFI_SUCCESS Mode information returned.
|
|
@retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
|
|
video mode.
|
|
@retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
|
|
@retval EFI_INVALID_PARAMETER One of the input args was NULL.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FbGopGraphicsOutputQueryMode (
|
|
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
|
|
IN UINT32 ModeNumber,
|
|
OUT UINTN *SizeOfInfo,
|
|
OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
|
|
)
|
|
{
|
|
FB_VIDEO_DEV *FbGopPrivate;
|
|
FB_VIDEO_MODE_DATA *ModeData;
|
|
|
|
FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
|
|
|
|
if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
|
|
sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
|
|
);
|
|
if (NULL == *Info) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
*SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
|
|
|
|
ModeData = &FbGopPrivate->ModeData[ModeNumber];
|
|
(*Info)->Version = 0;
|
|
(*Info)->HorizontalResolution = ModeData->HorizontalResolution;
|
|
(*Info)->VerticalResolution = ModeData->VerticalResolution;
|
|
(*Info)->PixelFormat = ModeData->PixelFormat;
|
|
CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(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.
|
|
|
|
@retval EFI_SUCCESS Graphics mode was changed.
|
|
@retval EFI_DEVICE_ERROR The device had an error and could not complete the
|
|
request.
|
|
@retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FbGopGraphicsOutputSetMode (
|
|
IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
|
|
IN UINT32 ModeNumber
|
|
)
|
|
{
|
|
FB_VIDEO_DEV *FbGopPrivate;
|
|
FB_VIDEO_MODE_DATA *ModeData;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
|
|
|
|
if (This == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
|
|
|
|
ModeData = &FbGopPrivate->ModeData[ModeNumber];
|
|
|
|
if (ModeNumber >= This->Mode->MaxMode) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (ModeNumber == This->Mode->Mode) {
|
|
//
|
|
// Clear screen to black
|
|
//
|
|
ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
|
|
FbGopGraphicsOutputVbeBlt (
|
|
This,
|
|
&Background,
|
|
EfiBltVideoFill,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
ModeData->HorizontalResolution,
|
|
ModeData->VerticalResolution,
|
|
0
|
|
);
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
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
|
|
|
|
**/
|
|
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);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Worker function to block transfer for VBE device.
|
|
|
|
@param FbGopPrivate Instance of FB_VIDEO_DEV
|
|
@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.
|
|
@param Mode Mode data.
|
|
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter passed in
|
|
@retval EFI_SUCCESS Blt operation success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
FbGopVbeBltWorker (
|
|
IN FB_VIDEO_DEV *FbGopPrivate,
|
|
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,
|
|
IN FB_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;
|
|
|
|
PciIo = FbGopPrivate->PciIo;
|
|
|
|
VbeFrameBuffer = FbGopPrivate->VbeFrameBuffer;
|
|
MemAddress = Mode->LinearFrameBuffer;
|
|
BytesPerScanLine = Mode->BytesPerScanLine;
|
|
VbePixelWidth = Mode->BitsPerPixel / 8;
|
|
BltUint8 = (UINT8 *) BltBuffer;
|
|
TotalBytes = Width * VbePixelWidth;
|
|
|
|
if (((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 = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;
|
|
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: ;
|
|
}
|
|
|
|
gBS->RestoreTPL (OriginalTPL);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
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.
|
|
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter passed in
|
|
@retval EFI_SUCCESS Blt operation success
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FbGopGraphicsOutputVbeBlt (
|
|
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
|
|
)
|
|
{
|
|
FB_VIDEO_DEV *FbGopPrivate;
|
|
FB_VIDEO_MODE_DATA *Mode;
|
|
|
|
if (This == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
|
|
Mode = &FbGopPrivate->ModeData[This->Mode->Mode];
|
|
|
|
return FbGopVbeBltWorker (
|
|
FbGopPrivate,
|
|
BltBuffer,
|
|
BltOperation,
|
|
SourceX,
|
|
SourceY,
|
|
DestinationX,
|
|
DestinationY,
|
|
Width,
|
|
Height,
|
|
Delta,
|
|
Mode
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
The user Entry Point for module UefiFbGop. The user code starts with this function.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval other Some error occurs when executing this entry point.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
FbGopEntryPoint(
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HOB_GUID_TYPE *GuidHob;
|
|
|
|
//
|
|
// Find the frame buffer information guid hob
|
|
//
|
|
GuidHob = GetFirstGuidHob (&gUefiFrameBufferInfoGuid);
|
|
if (GuidHob != NULL) {
|
|
//
|
|
// Install driver model protocol(s).
|
|
//
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gFbGopDriverBinding,
|
|
ImageHandle,
|
|
&gFbGopComponentName,
|
|
&gFbGopComponentName2
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
} else {
|
|
DEBUG ((EFI_D_ERROR, "No FrameBuffer information from coreboot. NO GOP driver !!!\n"));
|
|
Status = EFI_ABORTED;
|
|
}
|
|
return Status;
|
|
}
|
|
|