Home | History | Annotate | Download | only in UefiBootManagerLib
      1 /** @file
      2   Library functions which relate with connecting the device.
      3 
      4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "InternalBm.h"
     16 
     17 /**
     18   Connect all the drivers to all the controllers.
     19 
     20   This function makes sure all the current system drivers manage the correspoinding
     21   controllers if have. And at the same time, makes sure all the system controllers
     22   have driver to manage it if have.
     23 **/
     24 VOID
     25 BmConnectAllDriversToAllControllers (
     26   VOID
     27   )
     28 {
     29   EFI_STATUS  Status;
     30   UINTN       HandleCount;
     31   EFI_HANDLE  *HandleBuffer;
     32   UINTN       Index;
     33 
     34   do {
     35     //
     36     // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
     37     //
     38     gBS->LocateHandleBuffer (
     39            AllHandles,
     40            NULL,
     41            NULL,
     42            &HandleCount,
     43            &HandleBuffer
     44            );
     45 
     46     for (Index = 0; Index < HandleCount; Index++) {
     47       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
     48     }
     49 
     50     if (HandleBuffer != NULL) {
     51       FreePool (HandleBuffer);
     52     }
     53 
     54     //
     55     // Check to see if it's possible to dispatch an more DXE drivers.
     56     // The above code may have made new DXE drivers show up.
     57     // If any new driver is dispatched (Status == EFI_SUCCESS) and we will try
     58     // the connect again.
     59     //
     60     Status = gDS->Dispatch ();
     61 
     62   } while (!EFI_ERROR (Status));
     63 }
     64 
     65 /**
     66   This function will connect all the system driver to controller
     67   first, and then special connect the default console, this make
     68   sure all the system controller available and the platform default
     69   console connected.
     70 
     71 **/
     72 VOID
     73 EFIAPI
     74 EfiBootManagerConnectAll (
     75   VOID
     76   )
     77 {
     78   //
     79   // Connect the platform console first
     80   //
     81   EfiBootManagerConnectAllDefaultConsoles ();
     82 
     83   //
     84   // Generic way to connect all the drivers
     85   //
     86   BmConnectAllDriversToAllControllers ();
     87 
     88   //
     89   // Here we have the assumption that we have already had
     90   // platform default console
     91   //
     92   EfiBootManagerConnectAllDefaultConsoles ();
     93 }
     94 
     95 /**
     96   This function will create all handles associate with every device
     97   path node. If the handle associate with one device path node can not
     98   be created successfully, then still give chance to do the dispatch,
     99   which load the missing drivers if possible.
    100 
    101   @param  DevicePathToConnect   The device path which will be connected, it can be
    102                                 a multi-instance device path
    103   @param  MatchingHandle        Return the controller handle closest to the DevicePathToConnect
    104 
    105   @retval EFI_SUCCESS            All handles associate with every device path node
    106                                  have been created.
    107   @retval EFI_OUT_OF_RESOURCES   There is no resource to create new handles.
    108   @retval EFI_NOT_FOUND          Create the handle associate with one device path
    109                                  node failed.
    110   @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device
    111                                  drivers on the DevicePath.
    112 **/
    113 EFI_STATUS
    114 EFIAPI
    115 EfiBootManagerConnectDevicePath (
    116   IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect,
    117   OUT EFI_HANDLE                *MatchingHandle          OPTIONAL
    118   )
    119 {
    120   EFI_STATUS                Status;
    121   EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;
    122   EFI_HANDLE                Handle;
    123   EFI_HANDLE                PreviousHandle;
    124   EFI_TPL                   CurrentTpl;
    125 
    126   if (DevicePathToConnect == NULL) {
    127     return EFI_INVALID_PARAMETER;
    128   }
    129 
    130   CurrentTpl = EfiGetCurrentTpl ();
    131   //
    132   // Start the real work of connect with RemainingDevicePath
    133   //
    134   PreviousHandle = NULL;
    135   do {
    136     //
    137     // Find the handle that best matches the Device Path. If it is only a
    138     // partial match the remaining part of the device path is returned in
    139     // RemainingDevicePath.
    140     //
    141     RemainingDevicePath = DevicePathToConnect;
    142     Status              = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
    143     if (!EFI_ERROR (Status)) {
    144       if (Handle == PreviousHandle) {
    145         //
    146         // If no forward progress is made try invoking the Dispatcher.
    147         // A new FV may have been added to the system an new drivers
    148         // may now be found.
    149         // Status == EFI_SUCCESS means a driver was dispatched
    150         // Status == EFI_NOT_FOUND means no new drivers were dispatched
    151         //
    152         if (CurrentTpl == TPL_APPLICATION) {
    153           Status = gDS->Dispatch ();
    154         } else {
    155           //
    156           // Always return EFI_NOT_FOUND here
    157           // to prevent dead loop when control handle is found but connection failded case
    158           //
    159           Status = EFI_NOT_FOUND;
    160         }
    161       }
    162 
    163 
    164       if (!EFI_ERROR (Status)) {
    165         PreviousHandle = Handle;
    166         //
    167         // Connect all drivers that apply to Handle and RemainingDevicePath,
    168         // the Recursive flag is FALSE so only one level will be expanded.
    169         //
    170         // If ConnectController fails to find a driver, then still give the chance to
    171         // do dispatch, because partial RemainingDevicePath may be in the new FV
    172         //
    173         // 1. If the connect fail, RemainingDevicepath and handle will not
    174         //    change, so next time will do the dispatch, then dispatch's status
    175         //    will take effect
    176         // 2. If the connect success, the RemainingDevicepath and handle will
    177         //    change, then avoid the dispatch, we have chance to continue the
    178         //    next connection
    179         //
    180         Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
    181         if (Status == EFI_NOT_FOUND) {
    182           Status = EFI_SUCCESS;
    183         }
    184         if (MatchingHandle != NULL) {
    185           *MatchingHandle = Handle;
    186         }
    187       }
    188     }
    189     //
    190     // Loop until RemainingDevicePath is an empty device path
    191     //
    192   } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
    193 
    194   ASSERT (EFI_ERROR (Status) || IsDevicePathEnd (RemainingDevicePath));
    195 
    196   return Status;
    197 }
    198 
    199 /**
    200   This function will disconnect all current system handles.
    201 
    202   gBS->DisconnectController() is invoked for each handle exists in system handle buffer.
    203   If handle is a bus type handle, all childrens also are disconnected recursively by
    204   gBS->DisconnectController().
    205 **/
    206 VOID
    207 EFIAPI
    208 EfiBootManagerDisconnectAll (
    209   VOID
    210   )
    211 {
    212   UINTN       HandleCount;
    213   EFI_HANDLE  *HandleBuffer;
    214   UINTN       Index;
    215 
    216   //
    217   // Disconnect all
    218   //
    219   gBS->LocateHandleBuffer (
    220          AllHandles,
    221          NULL,
    222          NULL,
    223          &HandleCount,
    224          &HandleBuffer
    225          );
    226   for (Index = 0; Index < HandleCount; Index++) {
    227     gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
    228   }
    229 
    230   if (HandleBuffer != NULL) {
    231     FreePool (HandleBuffer);
    232   }
    233 }
    234 
    235 /**
    236   Connect the specific Usb device which match the short form device path,
    237   and whose bus is determined by Host Controller (Uhci or Ehci).
    238 
    239   @param  DevicePath             A short-form device path that starts with the first
    240                                  element being a USB WWID or a USB Class device
    241                                  path
    242 
    243   @return EFI_INVALID_PARAMETER  DevicePath is NULL pointer.
    244                                  DevicePath is not a USB device path.
    245 
    246   @return EFI_SUCCESS            Success to connect USB device
    247   @return EFI_NOT_FOUND          Fail to find handle for USB controller to connect.
    248 
    249 **/
    250 EFI_STATUS
    251 BmConnectUsbShortFormDevicePath (
    252   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
    253   )
    254 {
    255   EFI_STATUS                            Status;
    256   EFI_HANDLE                            *Handles;
    257   UINTN                                 HandleCount;
    258   UINTN                                 Index;
    259   EFI_PCI_IO_PROTOCOL                   *PciIo;
    260   UINT8                                 Class[3];
    261   BOOLEAN                               AtLeastOneConnected;
    262 
    263   //
    264   // Check the passed in parameters
    265   //
    266   if (DevicePath == NULL) {
    267     return EFI_INVALID_PARAMETER;
    268   }
    269 
    270   if ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
    271       ((DevicePathSubType (DevicePath) != MSG_USB_CLASS_DP) && (DevicePathSubType (DevicePath) != MSG_USB_WWID_DP))
    272      ) {
    273     return EFI_INVALID_PARAMETER;
    274   }
    275 
    276   //
    277   // Find the usb host controller firstly, then connect with the remaining device path
    278   //
    279   AtLeastOneConnected = FALSE;
    280   Status = gBS->LocateHandleBuffer (
    281                   ByProtocol,
    282                   &gEfiPciIoProtocolGuid,
    283                   NULL,
    284                   &HandleCount,
    285                   &Handles
    286                   );
    287   if (!EFI_ERROR (Status)) {
    288     for (Index = 0; Index < HandleCount; Index++) {
    289       Status = gBS->HandleProtocol (
    290                       Handles[Index],
    291                       &gEfiPciIoProtocolGuid,
    292                       (VOID **) &PciIo
    293                       );
    294       if (!EFI_ERROR (Status)) {
    295         //
    296         // Check whether the Pci device is the wanted usb host controller
    297         //
    298         Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
    299         if (!EFI_ERROR (Status) &&
    300             ((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1]))
    301            ) {
    302           Status = gBS->ConnectController (
    303                           Handles[Index],
    304                           NULL,
    305                           DevicePath,
    306                           FALSE
    307                           );
    308           if (!EFI_ERROR(Status)) {
    309             AtLeastOneConnected = TRUE;
    310           }
    311         }
    312       }
    313     }
    314 
    315     if (Handles != NULL) {
    316       FreePool (Handles);
    317     }
    318   }
    319 
    320   return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND;
    321 }
    322