summaryrefslogtreecommitdiff
path: root/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c
diff options
context:
space:
mode:
Diffstat (limited to 'IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c')
-rw-r--r--IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c653
1 files changed, 653 insertions, 0 deletions
diff --git a/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c b/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c
new file mode 100644
index 0000000000..daee1fb510
--- /dev/null
+++ b/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c
@@ -0,0 +1,653 @@
+/*++
+
+Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved. <BR>
+This software and associated documentation (if any) is furnished
+under a license and may only be used or copied in accordance
+with the terms of the license. Except as permitted by such
+license, no part of this software or documentation may be
+reproduced, stored in a retrieval system, or transmitted in any
+form or by any means without the express written consent of
+Intel Corporation.
+
+Module Name:
+
+ IsaBus.c
+
+Abstract:
+
+ Discovers all the ISA Controllers and their resources by using the ISA PnP
+ Protocol, produces an instance of the ISA I/O Protocol for every ISA
+ Controller found, loads and initializes all ISA Device Drivers, matches ISA
+ Device Drivers with their respective ISA Controllers in a deterministic
+ manner, and informs a ISA Device Driver when it is to start managing an ISA
+ Controller.
+
+Revision History:
+
+--*/
+
+#include "InternalIsaBus.h"
+
+//
+// ISA Bus Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gIsaBusControllerDriver = {
+ IsaBusControllerDriverSupported,
+ IsaBusControllerDriverStart,
+ IsaBusControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_STATUS
+EFIAPI
+IsaBusControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ )
+/*++
+
+ Routine Description:
+
+ This function checks to see if a controller can be managed by the ISA Bus
+ Driver. This is done by checking to see if the controller supports the
+ EFI_PCI_IO_PROTOCOL protocol, and then looking at the PCI Configuration
+ Header to see if the device is a PCI to ISA bridge. The class code of
+ PCI to ISA bridge: Base class 06h, Sub class 01h Interface 00h
+
+ Arguments:
+
+ This - The EFI_DRIVER_BINDING_PROTOCOL instance.
+ Controller - The handle of the device to check.
+ RemainingDevicePath - A pointer to the remaining portion of a device path.
+
+ Returns:
+
+ EFI_SUCCESS - The device is supported by this driver.
+ EFI_UNSUPPORTED - The device is not supported by this driver.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_ISA_ACPI_PROTOCOL *IsaAcpi;
+
+ //
+ // If RemainingDevicePath is not NULL, it should verify that the first device
+ // path node in RemainingDevicePath is an ACPI Device path node
+ //
+ if (RemainingDevicePath != NULL) {
+ if (RemainingDevicePath->Type != ACPI_DEVICE_PATH) {
+ return EFI_UNSUPPORTED;
+ } else if (RemainingDevicePath->SubType == ACPI_DP) {
+ if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_HID_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ } else if (RemainingDevicePath->SubType == ACPI_EXTENDED_DP) {
+ if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_EXTENDED_HID_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ //
+ // Test the existence of DEVICE_PATH protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the Isa Acpi protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaAcpiProtocolGuid,
+ (VOID **) &IsaAcpi,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaAcpiProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+IsaBusControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
+ )
+/*++
+
+ Routine Description:
+
+ This function tells the ISA Bus Driver to start managing a PCI to ISA
+ Bridge controller.
+
+ Arguments:
+
+ This - The EFI_DRIVER_BINDING_PROTOCOL instance.
+ Controller - A handle to the device being started.
+ RemainingDevicePath - A pointer to the remaining portion of a device path.
+
+ Returns:
+
+ EFI_SUCCESS - The device was started.
+ EFI_UNSUPPORTED - The device is not supported.
+ EFI_DEVICE_ERROR - The device could not be started due to a device error.
+ EFI_ALREADY_STARTED - The device has already been started.
+ EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ resources.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_ISA_ACPI_PROTOCOL *IsaAcpi;
+ EFI_ISA_ACPI_DEVICE_ID *IsaDevice;
+ EFI_ISA_ACPI_RESOURCE_LIST *ResourceList;
+ EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest;
+
+ //
+ // Local variables declaration for StatusCode reporting
+ //
+ EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA AllocFailExtendedData;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathData;
+
+ BootScriptSaveInformationAsciiString (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ "IsaBusBindingStartBegin"
+ );
+
+ //
+ // Initialize status code structure
+ //
+ AllocFailExtendedData.DataHeader.HeaderSize = sizeof (EFI_STATUS_CODE_DATA);
+ AllocFailExtendedData.DataHeader.Size = sizeof (EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA);
+ CopyMem (
+ &AllocFailExtendedData.DataHeader.Type,
+ &gEfiStatusCodeSpecificDataGuid,
+ sizeof (EFI_GUID)
+ );
+
+ //
+ // Open Device Path Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+ //
+ // Open Pci IO Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Close opened protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+ //
+ // Open ISA Acpi Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaAcpiProtocolGuid,
+ (VOID **) &IsaAcpi,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ //
+ // Close opened protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+ //
+ // The IsaBus driver will use memory below 16M, which is not tested yet,
+ // so call CompatibleRangeTest to test them. Since memory below 1M should
+ // be reserved to CSM, and 15M~16M might be reserved for Isa hole, test 1M
+ // ~15M here
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (VOID **) &GenMemoryTest
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = GenMemoryTest->CompatibleRangeTest (
+ GenMemoryTest,
+ 0x100000,
+ 0xE00000
+ );
+ }
+ //
+ // Report Status Code here since we will initialize the host controller
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_LPC | EFI_IOB_PC_INIT),
+ ParentDevicePath
+ );
+
+ //
+ // first init ISA interface
+ //
+ IsaAcpi->InterfaceInit (IsaAcpi);
+
+ //
+ // Report Status Code here since we will enable the host controller
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_LPC | EFI_IOB_PC_ENABLE),
+ ParentDevicePath
+ );
+
+ //
+ // Create each ISA device handle in this ISA bus
+ //
+ IsaDevice = NULL;
+ do {
+ Status = IsaAcpi->DeviceEnumerate (IsaAcpi, &IsaDevice);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Get current resource of this ISA device
+ //
+ ResourceList = NULL;
+ Status = IsaAcpi->GetCurResource (IsaAcpi, IsaDevice, &ResourceList);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Create handle for this ISA device
+ //
+ Status = IsaCreateDevice (
+ This,
+ Controller,
+ PciIo,
+ ParentDevicePath,
+ ResourceList,
+ &DevicePathData
+ //&AllocFailExtendedData.DevicePath
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Initialize ISA device
+ //
+ IsaAcpi->InitDevice (IsaAcpi, IsaDevice);
+
+ //
+ // Set resources for this ISA device
+ //
+ Status = IsaAcpi->SetResource (IsaAcpi, IsaDevice, ResourceList);
+
+ //
+ // Report Status Code here when failed to resource conflicts
+ //
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ //
+ // It's hard to tell which resource conflicts
+ //
+ AllocFailExtendedData.Bar = 0;
+ AllocFailExtendedData.ReqRes = NULL;
+ AllocFailExtendedData.AllocRes = NULL;
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE,
+ (EFI_IO_BUS_LPC | EFI_IOB_EC_RESOURCE_CONFLICT),
+ DevicePathData
+ );
+
+ }
+ //
+ // Set power for this ISA device
+ //
+ IsaAcpi->SetPower (IsaAcpi, IsaDevice, TRUE);
+
+ //
+ // Enable this ISA device
+ //
+ IsaAcpi->EnableDevice (IsaAcpi, IsaDevice, TRUE);
+
+ } while (TRUE);
+
+ BootScriptSaveInformationAsciiString (
+ EFI_ACPI_S3_RESUME_SCRIPT_TABLE,
+ "IsaBusBindingStartEnd"
+ );
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+IsaBusControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE * ChildHandleBuffer OPTIONAL
+ )
+/*++
+
+ Routine Description:
+
+ This function tells the ISA Bus Driver to stop managing a PCI to ISA
+ Bridge controller.
+
+ Arguments:
+
+ This - The EFI_DRIVER_BINDING_PROTOCOL instance.
+ Controller - A handle to the device being stopped.
+ NumberOfChindren - The number of child device handles in ChildHandleBuffer.
+ ChildHandleBuffer - An array of child handles to be freed.
+
+
+ Returns:
+
+ EFI_SUCCESS - The device was stopped.
+ EFI_DEVICE_ERROR - The device could not be stopped due to a device error.
+ EFI_NOT_STARTED - The device has not been started.
+ EFI_INVALID_PARAMETER - One of the parameters has an invalid value.
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ resources.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+ ISA_IO_DEVICE *IsaIoDevice;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaAcpiProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+ }
+ //
+ // Complete all outstanding transactions to Controller.
+ // Don't allow any new transaction to Controller to be started.
+ //
+ //
+ // Stop all the children
+ // Find all the ISA devices that were discovered on this PCI to ISA Bridge
+ // with the Start() function.
+ //
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (IsaIo);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ IsaIoDevice->DevicePath,
+ &gEfiIsaIoProtocolGuid,
+ &IsaIoDevice->IsaIo,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ gBS->FreePool (IsaIoDevice->DevicePath);
+ gBS->FreePool (IsaIoDevice);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+//
+// Internal Function
+//
+EFI_STATUS
+IsaCreateDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_ISA_ACPI_RESOURCE_LIST *IsaDeviceResourceList,
+ OUT EFI_DEVICE_PATH_PROTOCOL **ChildDevicePath
+ )
+/*++
+
+ Routine Description:
+
+ Create ISA device found by IsaPnpProtocol
+
+ Arguments:
+
+ This - The EFI_DRIVER_BINDING_PROTOCOL instance.
+ Controller - The handle of ISA bus controller(PCI to ISA bridge)
+ PciIo - The Pointer to the PCI protocol
+ ParentDevicePath - Device path of the ISA bus controller
+ IsaDeviceResourceList - The resource list of the ISA device
+ ChildDevicePath - The pointer to the child device.
+
+ Returns:
+
+ EFI_SUCCESS - Create the child device.
+ EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ resources.
+ EFI_DEVICE_ERROR - Can not create child device.
+
+--*/
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+ EFI_DEV_PATH Node;
+
+ //
+ // Initialize the PCI_IO_DEVICE structure
+ //
+ IsaIoDevice = AllocateZeroPool (sizeof (ISA_IO_DEVICE));
+ if (IsaIoDevice == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IsaIoDevice->Signature = ISA_IO_DEVICE_SIGNATURE;
+ IsaIoDevice->Handle = NULL;
+ IsaIoDevice->PciIo = PciIo;
+
+ //
+ // Initialize the ISA I/O instance structure
+ //
+ Status = InitializeIsaIoInstance (IsaIoDevice, IsaDeviceResourceList);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (IsaIoDevice);
+ return Status;
+ }
+ //
+ // Build the child device path
+ //
+ Node.DevPath.Type = ACPI_DEVICE_PATH;
+ Node.DevPath.SubType = ACPI_DP;
+ SetDevicePathNodeLength (&Node.DevPath, sizeof (ACPI_HID_DEVICE_PATH));
+ Node.Acpi.HID = IsaDeviceResourceList->Device.HID;
+ Node.Acpi.UID = IsaDeviceResourceList->Device.UID;
+
+ IsaIoDevice->DevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ &Node.DevPath
+ );
+
+ if (IsaIoDevice->DevicePath == NULL) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ *ChildDevicePath = IsaIoDevice->DevicePath;
+
+ //
+ // Create a child handle and attach the DevicePath,
+ // PCI I/O, and Controller State
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &IsaIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ IsaIoDevice->DevicePath,
+ &gEfiIsaIoProtocolGuid,
+ &IsaIoDevice->IsaIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ IsaIoDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ IsaIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ IsaIoDevice->DevicePath,
+ &gEfiIsaIoProtocolGuid,
+ &IsaIoDevice->IsaIo,
+ NULL
+ );
+ }
+
+Done:
+
+ if (EFI_ERROR (Status)) {
+ if (IsaIoDevice->DevicePath != NULL) {
+ gBS->FreePool (IsaIoDevice->DevicePath);
+ }
+
+ gBS->FreePool (IsaIoDevice);
+ }
+
+ return Status;
+}