pcidevicesupport.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,352 行 · 第 1/3 页

C
1,352
字号

  EFI_LIST_ENTRY  *CurrentLink;
  PCI_IO_DEVICE   *Temp;

  while (!IsListEmpty (&Bridge->ChildList)) {

    CurrentLink = Bridge->ChildList.ForwardLink;
    Temp        = PCI_IO_DEVICE_FROM_LINK (CurrentLink);

    //
    // Check if the current node has been deregistered before
    // If it is not, then deregister it
    //
    if (Temp->Registered) {
      DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);
    }
    
    //
    // Remove this node from the linked list
    //
    RemoveEntryList (CurrentLink);

    if (!IsListEmpty (&Temp->ChildList)) {
      RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
    }

    FreePciDevice (Temp);
  }

  return EFI_SUCCESS;
}

EFI_STATUS
DeRegisterPciDevice (
  IN  EFI_HANDLE                     Controller,
  IN  EFI_HANDLE                     Handle
  )
/*++

Routine Description:

  This function is used to de-register the PCI device from the EFI,
  That includes un-installing PciIo protocol from the specified PCI 
  device handle.

Arguments:

  Controller   - An efi handle.
  Handle       - An efi handle.

Returns:

  None

--*/
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  EFI_PCI_IO_PROTOCOL             *PciIo;
  EFI_STATUS                      Status;
  PCI_IO_DEVICE                   *PciIoDevice;
  PCI_IO_DEVICE                   *Node;
  EFI_LIST_ENTRY                  *CurrentLink;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;

  Status = gBS->OpenProtocol (
                  Handle,
                  &gEfiPciIoProtocolGuid,
                  (VOID **) &PciIo,
                  gPciBusDriverBinding.DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );
  if (!EFI_ERROR (Status)) {
    PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);

    //
    // If it is already de-registered
    //
    if (!PciIoDevice->Registered) {
      return EFI_SUCCESS;
    }

    //
    // If it is PPB, first de-register its children
    //

    if (!IsListEmpty (&PciIoDevice->ChildList)) {

      CurrentLink = PciIoDevice->ChildList.ForwardLink;

      while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {
        Node    = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
        Status  = DeRegisterPciDevice (Controller, Node->Handle);

        if (EFI_ERROR (Status)) {
          return Status;
        }

        CurrentLink = CurrentLink->ForwardLink;
      }
    }
    //
    // Uninstall Pccard Hotplug GUID for Pccard device
    //
    UninstallPciHotplugGuid (PciIoDevice);

    //
    // Close the child handle
    //
    Status = gBS->CloseProtocol (
                    Controller,
                    &gEfiPciRootBridgeIoProtocolGuid,
                    gPciBusDriverBinding.DriverBindingHandle,
                    Handle
                    );

    //
    // Un-install the device path protocol and pci io protocol
    //
    if (PciIoDevice->BusOverride) {
      Status = gBS->UninstallMultipleProtocolInterfaces (
                      Handle,
                      &gEfiDevicePathProtocolGuid,
                      PciIoDevice->DevicePath,
                      &gEfiPciIoProtocolGuid,
                      &PciIoDevice->PciIo,
                      &gEfiBusSpecificDriverOverrideProtocolGuid,
                      &PciIoDevice->PciDriverOverride,
                      NULL
                      );
    } else {
      Status = gBS->UninstallMultipleProtocolInterfaces (
                      Handle,
                      &gEfiDevicePathProtocolGuid,
                      PciIoDevice->DevicePath,
                      &gEfiPciIoProtocolGuid,
                      &PciIoDevice->PciIo,
                      NULL
                      );
    }

    if (EFI_ERROR (Status)) {
      gBS->OpenProtocol (
            Controller,
            &gEfiPciRootBridgeIoProtocolGuid,
            (VOID **) &PciRootBridgeIo,
            gPciBusDriverBinding.DriverBindingHandle,
            Handle,
            EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
            );
      return Status;
    }
    
    //
    // The Device Driver should disable this device after disconnect
    // so the Pci Bus driver will not touch this device any more.
    // Restore the register field to the original value
    //
    PciIoDevice->Registered = FALSE;
    PciIoDevice->Handle     = NULL;
  } else {

    //
    // Handle may be closed before
    //
    return EFI_SUCCESS;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
StartPciDevicesOnBridge (
  IN EFI_HANDLE                          Controller,
  IN PCI_IO_DEVICE                       *RootBridge,
  IN EFI_DEVICE_PATH_PROTOCOL            *RemainingDevicePath,
  IN OUT UINT8                           *NumberOfChildren,
  IN OUT EFI_HANDLE                      *ChildHandleBuffer
  )
/*++

Routine Description:

  Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge

Arguments:

  Controller          - An efi handle.
  RootBridge          - A pointer to the PCI_IO_DEVICE.
  RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
  NumberOfChildren    - Children number.
  ChildHandleBuffer   - A pointer to the child handle buffer.

Returns:

  None

--*/
// TODO:    EFI_NOT_READY - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_NOT_FOUND - add return value to function comment
{
  PCI_IO_DEVICE             *Temp;
  PCI_IO_DEVICE             *PciIoDevice;
  EFI_DEV_PATH_PTR          Node;
  EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;
  EFI_STATUS                Status;
  EFI_LIST_ENTRY            *CurrentLink;
  UINT64                    Supports;

  CurrentLink = RootBridge->ChildList.ForwardLink;

  while (CurrentLink && CurrentLink != &RootBridge->ChildList) {

    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    if (RemainingDevicePath != NULL) {

      Node.DevPath = RemainingDevicePath;

      if (Node.Pci->Device != Temp->DeviceNumber || 
          Node.Pci->Function != Temp->FunctionNumber) {
        CurrentLink = CurrentLink->ForwardLink;
        continue;
      }

      //
      // Check if the device has been assigned with required resource
      //
      if (!Temp->Allocated) {
        return EFI_NOT_READY;
      }
      
      //
      // Check if the current node has been registered before
      // If it is not, register it
      //
      if (!Temp->Registered) {
        PciIoDevice = Temp;

        Status = RegisterPciDevice (
                  Controller,
                  PciIoDevice,
                  NULL
                  );

      }

      if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {
        ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;
        (*NumberOfChildren)++;
      }
      
      //
      // Get the next device path
      //
      CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath);
      if (EfiIsDevicePathEnd (CurrentDevicePath)) {
        return EFI_SUCCESS;
      }
  
      //
      // If it is a PPB
      //
      if (!IsListEmpty (&Temp->ChildList)) {
        Status = StartPciDevicesOnBridge (
                  Controller,
                  Temp,
                  CurrentDevicePath,
                  NumberOfChildren,
                  ChildHandleBuffer
                  );

        Temp->PciIo.Attributes (
                      &(Temp->PciIo),
                      EfiPciIoAttributeOperationSupported,
                      0,
                      &Supports
                      );
        Supports &= EFI_PCI_DEVICE_ENABLE;
        Temp->PciIo.Attributes (
                      &(Temp->PciIo),
                      EfiPciIoAttributeOperationEnable,
                      Supports,
                      NULL
                      );

        return Status;
      } else {

        //
        // Currently, the PCI bus driver only support PCI-PCI bridge
        //
        return EFI_UNSUPPORTED;
      }

    } else {

      //
      // If remaining device path is NULL,
      // try to enable all the pci devices under this bridge
      //

      if (!Temp->Registered && Temp->Allocated) {

        PciIoDevice = Temp;

        Status = RegisterPciDevice (
                  Controller,
                  PciIoDevice,
                  NULL
                  );

      }

      if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {
        ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;
        (*NumberOfChildren)++;
      }

      if (!IsListEmpty (&Temp->ChildList)) {
        Status = StartPciDevicesOnBridge (
                  Controller,
                  Temp,
                  RemainingDevicePath,
                  NumberOfChildren,
                  ChildHandleBuffer
                  );

        Temp->PciIo.Attributes (
                      &(Temp->PciIo),
                      EfiPciIoAttributeOperationSupported,
                      0,
                      &Supports
                      );
        Supports &= EFI_PCI_DEVICE_ENABLE;
        Temp->PciIo.Attributes (
                      &(Temp->PciIo),
                      EfiPciIoAttributeOperationEnable,
                      Supports,
                      NULL
                      );

      }

      CurrentLink = CurrentLink->ForwardLink;
      continue;
    }
  }

  return EFI_NOT_FOUND;
}

EFI_STATUS
StartPciDevices (
  IN EFI_HANDLE                         Controller,
  IN EFI_DEVICE_PATH_PROTOCOL           *RemainingDevicePath
  )
/*++

Routine Description:

  Start to manage the PCI device according to RemainingDevicePath
  If RemainingDevicePath == NULL, the PCI bus driver will start 
  to manage all the PCI devices it found previously

Arguments:
  Controller          - An efi handle.
  RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.

Returns:

  None

--*/
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  EFI_DEV_PATH_PTR  Node;
  PCI_IO_DEVICE     *RootBridge;
  EFI_LIST_ENTRY    *CurrentLink;

  if (RemainingDevicePath != NULL) {

    //
    // Check if the RemainingDevicePath is valid
    //
    Node.DevPath = RemainingDevicePath;
    if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
        Node.DevPath->SubType != HW_PCI_DP         &&
        DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)
        ) {
      return EFI_UNSUPPORTED;
    }
  }

  CurrentLink = gPciDevicePool.ForwardLink;

  while (CurrentLink && CurrentLink != &gPciDevicePool) {

    RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    //
    // Locate the right root bridge to start
    //
    if (RootBridge->Handle == Controller) {
      StartPciDevicesOnBridge (
        Controller,
        RootBridge,
        RemainingDevicePath,
        NULL,
        NULL
        );
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  return EFI_SUCCESS;
}

PCI_IO_DEVICE *
CreateRootBridge (
  IN EFI_HANDLE RootBridgeHandle
  )
/*++

Routine Description:


Arguments:
  RootBridgeHandle   - An efi handle.

Returns:

  None

--*/
{

  EFI_STATUS                      Status;
  PCI_IO_DEVICE                   *Dev;
  EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;
  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;

  Dev = NULL;
  Status = gBS->AllocatePool (
                  EfiBootServicesData,
                  sizeof (PCI_IO_DEVICE),
                  (VOID **) &Dev

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?