| /** @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> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #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 occurred 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; | |
| } |