/** Connect a Device Path and return the handle of the driver that support this DevicePath @param DevicePath Device Path of the File to connect @param Handle Handle of the driver that support this DevicePath @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath @retval EFI_SUCCESS A driver that matches the Device Path has been found @retval EFI_NOT_FOUND No handles match the search. @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL **/ EFI_STATUS BdsConnectDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL* DevicePath, OUT EFI_HANDLE *Handle, OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath ) { EFI_DEVICE_PATH* Remaining; EFI_DEVICE_PATH* NewDevicePath; EFI_STATUS Status; if ((DevicePath == NULL) || (Handle == NULL)) { return EFI_INVALID_PARAMETER; } do { Remaining = DevicePath; // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified // to point to the remaining part of the device path Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle); if (!EFI_ERROR (Status)) { // Recursive = FALSE: We do not want to start all the device tree Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); } /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling // NextDevicePathNode() will return an undetermined Device Path Node if (!IsDevicePathEnd (RemainingDevicePath)) { RemainingDevicePath = NextDevicePathNode (RemainingDevicePath); }*/ } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining)); if (!EFI_ERROR (Status)) { // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver // Binding Protocol are connected (such as DiskIo and SimpleFileSystem) Remaining = DevicePath; Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,&Remaining,Handle); if (!EFI_ERROR (Status)) { Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); if (EFI_ERROR (Status)) { // If the last node is a Memory Map Device Path just return EFI_SUCCESS. if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { Status = EFI_SUCCESS; } } } } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) { /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) { Status = EFI_SUCCESS; } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { Status = EFI_SUCCESS; }*/ //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath Status = EFI_SUCCESS; } else { Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath); if (!EFI_ERROR (Status)) { return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath); } } if (RemainingDevicePath) { *RemainingDevicePath = Remaining; } return Status; }
STATIC EFI_STATUS BdsConnectAndUpdateDevicePath ( IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, OUT EFI_HANDLE *Handle, OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath ) { EFI_DEVICE_PATH* Remaining; EFI_DEVICE_PATH* NewDevicePath; EFI_STATUS Status; EFI_HANDLE PreviousHandle; if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) { return EFI_INVALID_PARAMETER; } PreviousHandle = NULL; do { Remaining = *DevicePath; // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified // to point to the remaining part of the device path Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, 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 and new drivers // may now be found. // Status == EFI_SUCCESS means a driver was dispatched // Status == EFI_NOT_FOUND means no new drivers were dispatched // Status = gDS->Dispatch (); } if (!EFI_ERROR (Status)) { PreviousHandle = *Handle; // Recursive = FALSE: We do not want to start the whole device tree Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); } } } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining)); if (!EFI_ERROR (Status)) { // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver // Binding Protocol are connected (such as DiskIo and SimpleFileSystem) Remaining = *DevicePath; Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle); if (!EFI_ERROR (Status)) { Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); if (EFI_ERROR (Status)) { // If the last node is a Memory Map Device Path just return EFI_SUCCESS. if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { Status = EFI_SUCCESS; } } } } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) { /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) { Status = EFI_SUCCESS; } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { Status = EFI_SUCCESS; }*/ //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath Status = EFI_SUCCESS; } else { Status = TryRemovableDevice (*DevicePath, Handle, &NewDevicePath); if (!EFI_ERROR (Status)) { Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath); *DevicePath = NewDevicePath; return Status; } } if (RemainingDevicePath) { *RemainingDevicePath = Remaining; } return Status; }