/** @file | |
BDS Lib functions which relate with connect the device | |
Copyright (c) 2004 - 2013, 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 "InternalBdsLib.h" | |
/** | |
This function will connect all the system driver to controller | |
first, and then special connect the default console, this make | |
sure all the system controller available and the platform default | |
console connected. | |
**/ | |
VOID | |
EFIAPI | |
BdsLibConnectAll ( | |
VOID | |
) | |
{ | |
// | |
// Connect the platform console first | |
// | |
BdsLibConnectAllDefaultConsoles (); | |
// | |
// Generic way to connect all the drivers | |
// | |
BdsLibConnectAllDriversToAllControllers (); | |
// | |
// Here we have the assumption that we have already had | |
// platform default console | |
// | |
BdsLibConnectAllDefaultConsoles (); | |
} | |
/** | |
This function will connect all the system drivers to all controllers | |
first, and then connect all the console devices the system current | |
have. After this we should get all the device work and console available | |
if the system have console device. | |
**/ | |
VOID | |
BdsLibGenericConnectAll ( | |
VOID | |
) | |
{ | |
// | |
// Most generic way to connect all the drivers | |
// | |
BdsLibConnectAllDriversToAllControllers (); | |
BdsLibConnectAllConsoles (); | |
} | |
/** | |
This function will create all handles associate with every device | |
path node. If the handle associate with one device path node can not | |
be created successfully, then still give chance to do the dispatch, | |
which load the missing drivers if possible. | |
@param DevicePathToConnect The device path which will be connected, it can be | |
a multi-instance device path | |
@retval EFI_SUCCESS All handles associate with every device path node | |
have been created | |
@retval EFI_OUT_OF_RESOURCES There is no resource to create new handles | |
@retval EFI_NOT_FOUND Create the handle associate with one device path | |
node failed | |
**/ | |
EFI_STATUS | |
EFIAPI | |
BdsLibConnectDevicePath ( | |
IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath; | |
EFI_DEVICE_PATH_PROTOCOL *Instance; | |
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; | |
EFI_DEVICE_PATH_PROTOCOL *Next; | |
EFI_HANDLE Handle; | |
EFI_HANDLE PreviousHandle; | |
UINTN Size; | |
EFI_TPL CurrentTpl; | |
if (DevicePathToConnect == NULL) { | |
return EFI_SUCCESS; | |
} | |
CurrentTpl = EfiGetCurrentTpl (); | |
DevicePath = DuplicateDevicePath (DevicePathToConnect); | |
if (DevicePath == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyOfDevicePath = DevicePath; | |
do { | |
// | |
// The outer loop handles multi instance device paths. | |
// Only console variables contain multiple instance device paths. | |
// | |
// After this call DevicePath points to the next Instance | |
// | |
Instance = GetNextDevicePathInstance (&DevicePath, &Size); | |
if (Instance == NULL) { | |
FreePool (CopyOfDevicePath); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Next = Instance; | |
while (!IsDevicePathEndType (Next)) { | |
Next = NextDevicePathNode (Next); | |
} | |
SetDevicePathEndNode (Next); | |
// | |
// Start the real work of connect with RemainingDevicePath | |
// | |
PreviousHandle = NULL; | |
do { | |
// | |
// Find the handle that best matches the Device Path. If it is only a | |
// partial match the remaining part of the device path is returned in | |
// RemainingDevicePath. | |
// | |
RemainingDevicePath = Instance; | |
Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle); | |
if (!EFI_ERROR (Status)) { | |
if (Handle == PreviousHandle) { | |
// | |
// If no forward progress is made try invoking the Dispatcher. | |
// A new FV may have been added to the system an new drivers | |
// may now be found. | |
// Status == EFI_SUCCESS means a driver was dispatched | |
// Status == EFI_NOT_FOUND means no new drivers were dispatched | |
// | |
if (CurrentTpl == TPL_APPLICATION) { | |
// | |
// Dispatch calls LoadImage/StartImage which cannot run at TPL > TPL_APPLICATION | |
// | |
Status = gDS->Dispatch (); | |
} else { | |
// | |
// Always return EFI_NOT_FOUND here | |
// to prevent dead loop when control handle is found but connection failded case | |
// | |
Status = EFI_NOT_FOUND; | |
} | |
} | |
if (!EFI_ERROR (Status)) { | |
PreviousHandle = Handle; | |
// | |
// Connect all drivers that apply to Handle and RemainingDevicePath, | |
// the Recursive flag is FALSE so only one level will be expanded. | |
// | |
// Do not check the connect status here, if the connect controller fail, | |
// then still give the chance to do dispatch, because partial | |
// RemainingDevicepath may be in the new FV | |
// | |
// 1. If the connect fail, RemainingDevicepath and handle will not | |
// change, so next time will do the dispatch, then dispatch's status | |
// will take effect | |
// 2. If the connect success, the RemainingDevicepath and handle will | |
// change, then avoid the dispatch, we have chance to continue the | |
// next connection | |
// | |
gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE); | |
} | |
} | |
// | |
// Loop until RemainingDevicePath is an empty device path | |
// | |
} while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath)); | |
} while (DevicePath != NULL); | |
if (CopyOfDevicePath != NULL) { | |
FreePool (CopyOfDevicePath); | |
} | |
// | |
// All handle with DevicePath exists in the handle database | |
// | |
return Status; | |
} | |
/** | |
This function will connect all current system handles recursively. | |
gBS->ConnectController() service is invoked for each handle exist in system handler buffer. | |
If the handle is bus type handler, all childrens also will be connected recursively | |
by gBS->ConnectController(). | |
@retval EFI_SUCCESS All handles and it's child handle have been connected | |
@retval EFI_STATUS Error status returned by of gBS->LocateHandleBuffer(). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
BdsLibConnectAllEfi ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN HandleCount; | |
EFI_HANDLE *HandleBuffer; | |
UINTN Index; | |
Status = gBS->LocateHandleBuffer ( | |
AllHandles, | |
NULL, | |
NULL, | |
&HandleCount, | |
&HandleBuffer | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
for (Index = 0; Index < HandleCount; Index++) { | |
Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); | |
} | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This function will disconnect all current system handles. | |
gBS->DisconnectController() is invoked for each handle exists in system handle buffer. | |
If handle is a bus type handle, all childrens also are disconnected recursively by | |
gBS->DisconnectController(). | |
@retval EFI_SUCCESS All handles have been disconnected | |
@retval EFI_STATUS Error status returned by of gBS->LocateHandleBuffer(). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
BdsLibDisconnectAllEfi ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN HandleCount; | |
EFI_HANDLE *HandleBuffer; | |
UINTN Index; | |
// | |
// Disconnect all | |
// | |
Status = gBS->LocateHandleBuffer ( | |
AllHandles, | |
NULL, | |
NULL, | |
&HandleCount, | |
&HandleBuffer | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
for (Index = 0; Index < HandleCount; Index++) { | |
Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); | |
} | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Connects all drivers to all controllers. | |
This function make sure all the current system driver will manage | |
the correspoinding controllers if have. And at the same time, make | |
sure all the system controllers have driver to manage it if have. | |
**/ | |
VOID | |
EFIAPI | |
BdsLibConnectAllDriversToAllControllers ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
do { | |
// | |
// Connect All EFI 1.10 drivers following EFI 1.10 algorithm | |
// | |
BdsLibConnectAllEfi (); | |
// | |
// Check to see if it's possible to dispatch an more DXE drivers. | |
// The BdsLibConnectAllEfi () may have made new DXE drivers show up. | |
// If anything is Dispatched Status == EFI_SUCCESS and we will try | |
// the connect again. | |
// | |
Status = gDS->Dispatch (); | |
} while (!EFI_ERROR (Status)); | |
} | |
/** | |
Connect the specific Usb device which match the short form device path, | |
and whose bus is determined by Host Controller (Uhci or Ehci). | |
@param HostControllerPI Uhci (0x00) or Ehci (0x20) or Both uhci and ehci | |
(0xFF) | |
@param RemainingDevicePath a short-form device path that starts with the first | |
element being a USB WWID or a USB Class device | |
path | |
@return EFI_INVALID_PARAMETER RemainingDevicePath is NULL pointer. | |
RemainingDevicePath is not a USB device path. | |
Invalid HostControllerPI type. | |
@return EFI_SUCCESS Success to connect USB device | |
@return EFI_NOT_FOUND Fail to find handle for USB controller to connect. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
BdsLibConnectUsbDevByShortFormDP( | |
IN UINT8 HostControllerPI, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE *HandleArray; | |
UINTN HandleArrayCount; | |
UINTN Index; | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
UINT8 Class[3]; | |
BOOLEAN AtLeastOneConnected; | |
// | |
// Check the passed in parameters | |
// | |
if (RemainingDevicePath == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if ((DevicePathType (RemainingDevicePath) != MESSAGING_DEVICE_PATH) || | |
((DevicePathSubType (RemainingDevicePath) != MSG_USB_CLASS_DP) | |
&& (DevicePathSubType (RemainingDevicePath) != MSG_USB_WWID_DP) | |
)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (HostControllerPI != 0xFF && | |
HostControllerPI != 0x00 && | |
HostControllerPI != 0x20) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Find the usb host controller firstly, then connect with the remaining device path | |
// | |
AtLeastOneConnected = FALSE; | |
Status = gBS->LocateHandleBuffer ( | |
ByProtocol, | |
&gEfiPciIoProtocolGuid, | |
NULL, | |
&HandleArrayCount, | |
&HandleArray | |
); | |
if (!EFI_ERROR (Status)) { | |
for (Index = 0; Index < HandleArrayCount; Index++) { | |
Status = gBS->HandleProtocol ( | |
HandleArray[Index], | |
&gEfiPciIoProtocolGuid, | |
(VOID **)&PciIo | |
); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Check whether the Pci device is the wanted usb host controller | |
// | |
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class); | |
if (!EFI_ERROR (Status)) { | |
if ((PCI_CLASS_SERIAL == Class[2]) && | |
(PCI_CLASS_SERIAL_USB == Class[1])) { | |
if (HostControllerPI == Class[0] || HostControllerPI == 0xFF) { | |
Status = gBS->ConnectController ( | |
HandleArray[Index], | |
NULL, | |
RemainingDevicePath, | |
FALSE | |
); | |
if (!EFI_ERROR(Status)) { | |
AtLeastOneConnected = TRUE; | |
} | |
} | |
} | |
} | |
} | |
} | |
if (HandleArray != NULL) { | |
FreePool (HandleArray); | |
} | |
if (AtLeastOneConnected) { | |
return EFI_SUCCESS; | |
} | |
} | |
return EFI_NOT_FOUND; | |
} |