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