OvmfPkg: Add an Super IO bus driver
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1495 There is a plan to remove the IntelFrameworkModulePkg: https://bugzilla.tianocore.org/show_bug.cgi?id=1605 This patch will a new OVMF Super I/O bus driver which will create the below child devices: * COM 1 UART * COM 2 UART * PS/2 Keyboard and installs the Super I/O Protocol on them. Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Ray Ni <ray.ni@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Acked-by: Laszlo Ersek <lersek@redhat.com> Tested-by: Anthony PERARD <anthony.perard@citrix.com>
This commit is contained in:
405
OvmfPkg/SioBusDxe/SioService.c
Normal file
405
OvmfPkg/SioBusDxe/SioService.c
Normal file
@@ -0,0 +1,405 @@
|
||||
/** @file
|
||||
The SioBusDxe driver is used to create child devices on the ISA bus and
|
||||
installs the Super I/O protocols on them.
|
||||
|
||||
Copyright (c) 2019, 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 "SioBusDxe.h"
|
||||
|
||||
//
|
||||
// Super I/O Protocol interfaces
|
||||
//
|
||||
EFI_SIO_PROTOCOL mSioInterface = {
|
||||
SioRegisterAccess,
|
||||
SioGetResources,
|
||||
SioSetResources,
|
||||
SioPossibleResources,
|
||||
SioModify
|
||||
};
|
||||
|
||||
//
|
||||
// COM 1 UART Controller
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
SIO_RESOURCES_IO mCom1Resources = {
|
||||
{ { ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR }, 0x3F8, 8 },
|
||||
{ ACPI_END_TAG_DESCRIPTOR, 0 }
|
||||
};
|
||||
|
||||
//
|
||||
// COM 2 UART Controller
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
SIO_RESOURCES_IO mCom2Resources = {
|
||||
{ { ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR }, 0x2F8, 8 },
|
||||
{ ACPI_END_TAG_DESCRIPTOR, 0 }
|
||||
};
|
||||
|
||||
//
|
||||
// PS/2 Keyboard Controller
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
SIO_RESOURCES_IO mPs2KeyboardDeviceResources = {
|
||||
{ { ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR }, 0x60, 5 },
|
||||
{ ACPI_END_TAG_DESCRIPTOR, 0 }
|
||||
};
|
||||
|
||||
//
|
||||
// Table of SIO Controllers
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
SIO_DEVICE_INFO mDevicesInfo[] = {
|
||||
{
|
||||
EISA_PNP_ID (0x501),
|
||||
0,
|
||||
{ (ACPI_SMALL_RESOURCE_HEADER *) &mCom1Resources }
|
||||
}, // COM 1 UART Controller
|
||||
{
|
||||
EISA_PNP_ID (0x501),
|
||||
1,
|
||||
{ (ACPI_SMALL_RESOURCE_HEADER *) &mCom2Resources }
|
||||
}, // COM 2 UART Controller
|
||||
{
|
||||
EISA_PNP_ID(0x303),
|
||||
0,
|
||||
{ (ACPI_SMALL_RESOURCE_HEADER *) &mPs2KeyboardDeviceResources }
|
||||
} // PS/2 Keyboard Controller
|
||||
};
|
||||
|
||||
//
|
||||
// ACPI Device Path Node template
|
||||
//
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED
|
||||
ACPI_HID_DEVICE_PATH mAcpiDeviceNodeTemplate = {
|
||||
{ // Header
|
||||
ACPI_DEVICE_PATH,
|
||||
ACPI_DP,
|
||||
{
|
||||
(UINT8) (sizeof (ACPI_HID_DEVICE_PATH)),
|
||||
(UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)
|
||||
}
|
||||
},
|
||||
0x0, // HID
|
||||
0x0 // UID
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Provides a low level access to the registers for the Super I/O.
|
||||
|
||||
@param[in] This Indicates a pointer to the calling context.
|
||||
@param[in] Write Specifies the type of the register operation.
|
||||
If this parameter is TRUE, Value is interpreted
|
||||
as an input parameter and the operation is a
|
||||
register write. If this parameter is FALSE,
|
||||
Value is interpreted as an output parameter and
|
||||
the operation is a register read.
|
||||
@param[in] ExitCfgMode Exit Configuration Mode Indicator. If this
|
||||
parameter is set to TRUE, the Super I/O driver
|
||||
will turn off configuration mode of the Super
|
||||
I/O prior to returning from this function. If
|
||||
this parameter is set to FALSE, the Super I/O
|
||||
driver will leave Super I/O in the
|
||||
configuration mode. The Super I/O driver must
|
||||
track the current state of the Super I/O and
|
||||
enable the configuration mode of Super I/O if
|
||||
necessary prior to register access.
|
||||
@param[in] Register Register number.
|
||||
@param[in,out] Value If Write is TRUE, Value is a pointer to the
|
||||
buffer containing the byte of data to be
|
||||
written to the Super I/O register. If Write is
|
||||
FALSE, Value is a pointer to the destination
|
||||
buffer for the byte of data to be read from the
|
||||
Super I/O register.
|
||||
|
||||
@retval EFI_SUCCESS The operation completed successfully.
|
||||
@retval EFI_INVALID_PARAMETER The Value is NULL.
|
||||
@retval EFI_INVALID_PARAMETER Invalid Register number.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SioRegisterAccess (
|
||||
IN CONST EFI_SIO_PROTOCOL *This,
|
||||
IN BOOLEAN Write,
|
||||
IN BOOLEAN ExitCfgMode,
|
||||
IN UINT8 Register,
|
||||
IN OUT UINT8 *Value
|
||||
)
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Provides an interface to get a list of the current resources consumed by the
|
||||
device in the ACPI Resource Descriptor format.
|
||||
|
||||
GetResources() returns a list of resources currently consumed by the device.
|
||||
The ResourceList is a pointer to the buffer containing resource descriptors
|
||||
for the device. The descriptors are in the format of Small or Large ACPI
|
||||
resource descriptor as defined by ACPI specification (2.0 & 3.0). The buffer
|
||||
of resource descriptors is terminated with the 'End tag' resource descriptor.
|
||||
|
||||
@param[in] This Indicates a pointer to the calling context.
|
||||
@param[out] ResourceList A pointer to an ACPI resource descriptor list
|
||||
that defines the current resources used by the
|
||||
device.
|
||||
|
||||
@retval EFI_SUCCESS The operation completed successfully.
|
||||
@retval EFI_INVALID_PARAMETER ResourceList is NULL.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SioGetResources (
|
||||
IN CONST EFI_SIO_PROTOCOL *This,
|
||||
OUT ACPI_RESOURCE_HEADER_PTR *ResourceList
|
||||
)
|
||||
{
|
||||
SIO_DEV *SioDevice;
|
||||
|
||||
if (ResourceList == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
SioDevice = SIO_DEV_FROM_SIO (This);
|
||||
if (SioDevice->DeviceIndex < ARRAY_SIZE (mDevicesInfo)) {
|
||||
*ResourceList = mDevicesInfo[SioDevice->DeviceIndex].Resources;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the resources for the device.
|
||||
|
||||
@param[in] This Indicates a pointer to the calling context.
|
||||
@param[in] ResourceList Pointer to the ACPI resource descriptor list.
|
||||
|
||||
@retval EFI_SUCCESS The operation completed successfully.
|
||||
@retval EFI_INVALID_PARAMETER ResourceList is invalid.
|
||||
@retval EFI_ACCESS_DENIED Some of the resources in ResourceList are in
|
||||
use.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SioSetResources (
|
||||
IN CONST EFI_SIO_PROTOCOL *This,
|
||||
IN ACPI_RESOURCE_HEADER_PTR ResourceList
|
||||
)
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Provides a collection of resource descriptor lists. Each resource descriptor
|
||||
list in the collection defines a combination of resources that can
|
||||
potentially be used by the device.
|
||||
|
||||
@param[in] This Indicates a pointer to the calling context.
|
||||
@param[out] ResourceCollection Collection of the resource descriptor
|
||||
lists.
|
||||
|
||||
@retval EFI_SUCCESS The operation completed successfully.
|
||||
@retval EFI_INVALID_PARAMETER ResourceCollection is NULL.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SioPossibleResources (
|
||||
IN CONST EFI_SIO_PROTOCOL *This,
|
||||
OUT ACPI_RESOURCE_HEADER_PTR *ResourceCollection
|
||||
)
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Provides an interface for a table based programming of the Super I/O
|
||||
registers.
|
||||
|
||||
The Modify() function provides an interface for table based programming of
|
||||
the Super I/O registers. This function can be used to perform programming of
|
||||
multiple Super I/O registers with a single function call. For each table
|
||||
entry, the Register is read, its content is bitwise ANDed with AndMask, and
|
||||
then ORed with OrMask before being written back to the Register. The Super
|
||||
I/O driver must track the current state of the Super I/O and enable the
|
||||
configuration mode of Super I/O if necessary prior to table processing. Once
|
||||
the table is processed, the Super I/O device has to be returned to the
|
||||
original state.
|
||||
|
||||
@param[in] This Indicates a pointer to the calling context.
|
||||
@param[in] Command A pointer to an array of NumberOfCommands
|
||||
EFI_SIO_REGISTER_MODIFY structures. Each
|
||||
structure specifies a single Super I/O register
|
||||
modify operation.
|
||||
@param[in] NumberOfCommands Number of elements in the Command array.
|
||||
|
||||
@retval EFI_SUCCESS The operation completed successfully.
|
||||
@retval EFI_INVALID_PARAMETER Command is NULL.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
SioModify (
|
||||
IN CONST EFI_SIO_PROTOCOL *This,
|
||||
IN CONST EFI_SIO_REGISTER_MODIFY *Command,
|
||||
IN UINTN NumberOfCommands
|
||||
)
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Create the child device with a given device index.
|
||||
|
||||
@param[in] This The EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] Controller The handle of ISA bus controller.
|
||||
@param[in] PciIo The pointer to the PCI protocol.
|
||||
@param[in] ParentDevicePath Device path of the ISA bus controller.
|
||||
@param[in] DeviceIndex Index of the device supported by this driver.
|
||||
|
||||
@retval EFI_SUCCESS The child device has been created successfully.
|
||||
@retval Others Error occured during the child device creation.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
SioCreateChildDevice (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_PCI_IO_PROTOCOL *PciIo,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
|
||||
IN UINT32 DeviceIndex
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
SIO_DEV *SioDevice;
|
||||
|
||||
//
|
||||
// Initialize the SIO_DEV structure
|
||||
//
|
||||
SioDevice = AllocateZeroPool (sizeof (SIO_DEV));
|
||||
if (SioDevice == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
SioDevice->Signature = SIO_DEV_SIGNATURE;
|
||||
SioDevice->Handle = NULL;
|
||||
SioDevice->PciIo = PciIo;
|
||||
|
||||
//
|
||||
// Construct the child device path
|
||||
//
|
||||
mAcpiDeviceNodeTemplate.HID = mDevicesInfo[DeviceIndex].Hid;
|
||||
mAcpiDeviceNodeTemplate.UID = mDevicesInfo[DeviceIndex].Uid;
|
||||
SioDevice->DevicePath = AppendDevicePathNode (
|
||||
ParentDevicePath,
|
||||
(EFI_DEVICE_PATH_PROTOCOL *) &mAcpiDeviceNodeTemplate
|
||||
);
|
||||
if (SioDevice->DevicePath == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
CopyMem (&SioDevice->Sio, &mSioInterface, sizeof (EFI_SIO_PROTOCOL));
|
||||
SioDevice->DeviceIndex = DeviceIndex;
|
||||
|
||||
//
|
||||
// Create a child handle and install Device Path and Super I/O protocols
|
||||
//
|
||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||
&SioDevice->Handle,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
SioDevice->DevicePath,
|
||||
&gEfiSioProtocolGuid,
|
||||
&SioDevice->Sio,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
Controller,
|
||||
&gEfiPciIoProtocolGuid,
|
||||
(VOID **) &PciIo,
|
||||
This->DriverBindingHandle,
|
||||
SioDevice->Handle,
|
||||
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->UninstallMultipleProtocolInterfaces (
|
||||
SioDevice->Handle,
|
||||
&gEfiDevicePathProtocolGuid,
|
||||
SioDevice->DevicePath,
|
||||
&gEfiSioProtocolGuid,
|
||||
&SioDevice->Sio,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
Done:
|
||||
if (EFI_ERROR (Status)) {
|
||||
if (SioDevice->DevicePath != NULL) {
|
||||
FreePool (SioDevice->DevicePath);
|
||||
}
|
||||
|
||||
FreePool (SioDevice);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Create all the ISA child devices on the ISA bus controller (PCI to ISA
|
||||
bridge).
|
||||
|
||||
@param[in] This The EFI_DRIVER_BINDING_PROTOCOL instance.
|
||||
@param[in] Controller The handle of ISA bus controller.
|
||||
@param[in] PciIo The pointer to the PCI protocol.
|
||||
@param[in] ParentDevicePath Device path of the ISA bus controller.
|
||||
|
||||
@retval The number of child device that is successfully created.
|
||||
|
||||
**/
|
||||
UINT32
|
||||
SioCreateAllChildDevices (
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE Controller,
|
||||
IN EFI_PCI_IO_PROTOCOL *PciIo,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
|
||||
)
|
||||
{
|
||||
UINT32 Index;
|
||||
UINT32 ChildDeviceNumber;
|
||||
EFI_STATUS Status;
|
||||
|
||||
ChildDeviceNumber = 0;
|
||||
|
||||
for (Index = 0; Index < ARRAY_SIZE (mDevicesInfo); Index++) {
|
||||
Status = SioCreateChildDevice (
|
||||
This,
|
||||
Controller,
|
||||
PciIo,
|
||||
ParentDevicePath,
|
||||
Index
|
||||
);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
ChildDeviceNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
return ChildDeviceNumber;
|
||||
}
|
Reference in New Issue
Block a user