REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2361 Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com> Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Guomin Jiang <guomin.jiang@intel.com>
		
			
				
	
	
		
			399 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			399 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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;
 | |
| }
 |