Home | History | Annotate | Download | only in GenericBdsLib
      1 /** @file
      2   BDS Lib functions which relate with connect the device
      3 
      4 Copyright (c) 2004 - 2013, 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 "InternalBdsLib.h"
     16 
     17 
     18 /**
     19   This function will connect all the system driver to controller
     20   first, and then special connect the default console, this make
     21   sure all the system controller available and the platform default
     22   console connected.
     23 
     24 **/
     25 VOID
     26 EFIAPI
     27 BdsLibConnectAll (
     28   VOID
     29   )
     30 {
     31   //
     32   // Connect the platform console first
     33   //
     34   BdsLibConnectAllDefaultConsoles ();
     35 
     36   //
     37   // Generic way to connect all the drivers
     38   //
     39   BdsLibConnectAllDriversToAllControllers ();
     40 
     41   //
     42   // Here we have the assumption that we have already had
     43   // platform default console
     44   //
     45   BdsLibConnectAllDefaultConsoles ();
     46 }
     47 
     48 
     49 /**
     50   This function will connect all the system drivers to all controllers
     51   first, and then connect all the console devices the system current
     52   have. After this we should get all the device work and console available
     53   if the system have console device.
     54 
     55 **/
     56 VOID
     57 BdsLibGenericConnectAll (
     58   VOID
     59   )
     60 {
     61   //
     62   // Most generic way to connect all the drivers
     63   //
     64   BdsLibConnectAllDriversToAllControllers ();
     65   BdsLibConnectAllConsoles ();
     66 }
     67 
     68 /**
     69   This function will create all handles associate with every device
     70   path node. If the handle associate with one device path node can not
     71   be created successfully, then still give chance to do the dispatch,
     72   which load the missing drivers if possible.
     73 
     74   @param  DevicePathToConnect   The device path which will be connected, it can be
     75                                 a multi-instance device path
     76 
     77   @retval EFI_SUCCESS           All handles associate with every device path  node
     78                                 have been created
     79   @retval EFI_OUT_OF_RESOURCES  There is no resource to create new handles
     80   @retval EFI_NOT_FOUND         Create the handle associate with one device  path
     81                                 node failed
     82 
     83 **/
     84 EFI_STATUS
     85 EFIAPI
     86 BdsLibConnectDevicePath (
     87   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect
     88   )
     89 {
     90   EFI_STATUS                Status;
     91   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
     92   EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevicePath;
     93   EFI_DEVICE_PATH_PROTOCOL  *Instance;
     94   EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;
     95   EFI_DEVICE_PATH_PROTOCOL  *Next;
     96   EFI_HANDLE                Handle;
     97   EFI_HANDLE                PreviousHandle;
     98   UINTN                     Size;
     99   EFI_TPL                   CurrentTpl;
    100 
    101   if (DevicePathToConnect == NULL) {
    102     return EFI_SUCCESS;
    103   }
    104 
    105   CurrentTpl  = EfiGetCurrentTpl ();
    106 
    107   DevicePath        = DuplicateDevicePath (DevicePathToConnect);
    108   if (DevicePath == NULL) {
    109     return EFI_OUT_OF_RESOURCES;
    110   }
    111   CopyOfDevicePath  = DevicePath;
    112 
    113   do {
    114     //
    115     // The outer loop handles multi instance device paths.
    116     // Only console variables contain multiple instance device paths.
    117     //
    118     // After this call DevicePath points to the next Instance
    119     //
    120     Instance  = GetNextDevicePathInstance (&DevicePath, &Size);
    121     if (Instance == NULL) {
    122       FreePool (CopyOfDevicePath);
    123       return EFI_OUT_OF_RESOURCES;
    124     }
    125 
    126     Next      = Instance;
    127     while (!IsDevicePathEndType (Next)) {
    128       Next = NextDevicePathNode (Next);
    129     }
    130 
    131     SetDevicePathEndNode (Next);
    132 
    133     //
    134     // Start the real work of connect with RemainingDevicePath
    135     //
    136     PreviousHandle = NULL;
    137     do {
    138       //
    139       // Find the handle that best matches the Device Path. If it is only a
    140       // partial match the remaining part of the device path is returned in
    141       // RemainingDevicePath.
    142       //
    143       RemainingDevicePath = Instance;
    144       Status              = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
    145 
    146       if (!EFI_ERROR (Status)) {
    147         if (Handle == PreviousHandle) {
    148           //
    149           // If no forward progress is made try invoking the Dispatcher.
    150           // A new FV may have been added to the system an new drivers
    151           // may now be found.
    152           // Status == EFI_SUCCESS means a driver was dispatched
    153           // Status == EFI_NOT_FOUND means no new drivers were dispatched
    154           //
    155           if (CurrentTpl == TPL_APPLICATION) {
    156             //
    157             // Dispatch calls LoadImage/StartImage which cannot run at TPL > TPL_APPLICATION
    158             //
    159             Status = gDS->Dispatch ();
    160           } else {
    161             //
    162             // Always return EFI_NOT_FOUND here
    163             // to prevent dead loop when control handle is found but connection failded case
    164             //
    165             Status = EFI_NOT_FOUND;
    166           }
    167         }
    168 
    169         if (!EFI_ERROR (Status)) {
    170           PreviousHandle = Handle;
    171           //
    172           // Connect all drivers that apply to Handle and RemainingDevicePath,
    173           // the Recursive flag is FALSE so only one level will be expanded.
    174           //
    175           // Do not check the connect status here, if the connect controller fail,
    176           // then still give the chance to do dispatch, because partial
    177           // RemainingDevicepath may be in the new FV
    178           //
    179           // 1. If the connect fail, RemainingDevicepath and handle will not
    180           //    change, so next time will do the dispatch, then dispatch's status
    181           //    will take effect
    182           // 2. If the connect success, the RemainingDevicepath and handle will
    183           //    change, then avoid the dispatch, we have chance to continue the
    184           //    next connection
    185           //
    186           gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
    187         }
    188       }
    189       //
    190       // Loop until RemainingDevicePath is an empty device path
    191       //
    192     } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
    193 
    194   } while (DevicePath != NULL);
    195 
    196   if (CopyOfDevicePath != NULL) {
    197     FreePool (CopyOfDevicePath);
    198   }
    199   //
    200   // All handle with DevicePath exists in the handle database
    201   //
    202   return Status;
    203 }
    204 
    205 /**
    206   This function will connect all current system handles recursively.
    207 
    208   gBS->ConnectController() service is invoked for each handle exist in system handler buffer.
    209   If the handle is bus type handler, all childrens also will be connected recursively
    210   by gBS->ConnectController().
    211 
    212   @retval EFI_SUCCESS           All handles and it's child handle have been connected
    213   @retval EFI_STATUS            Error status returned by of gBS->LocateHandleBuffer().
    214 
    215 **/
    216 EFI_STATUS
    217 EFIAPI
    218 BdsLibConnectAllEfi (
    219   VOID
    220   )
    221 {
    222   EFI_STATUS  Status;
    223   UINTN       HandleCount;
    224   EFI_HANDLE  *HandleBuffer;
    225   UINTN       Index;
    226 
    227   Status = gBS->LocateHandleBuffer (
    228                   AllHandles,
    229                   NULL,
    230                   NULL,
    231                   &HandleCount,
    232                   &HandleBuffer
    233                   );
    234   if (EFI_ERROR (Status)) {
    235     return Status;
    236   }
    237 
    238   for (Index = 0; Index < HandleCount; Index++) {
    239     Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
    240   }
    241 
    242   if (HandleBuffer != NULL) {
    243     FreePool (HandleBuffer);
    244   }
    245 
    246   return EFI_SUCCESS;
    247 }
    248 
    249 /**
    250   This function will disconnect all current system handles.
    251 
    252   gBS->DisconnectController() is invoked for each handle exists in system handle buffer.
    253   If handle is a bus type handle, all childrens also are disconnected recursively by
    254   gBS->DisconnectController().
    255 
    256   @retval EFI_SUCCESS           All handles have been disconnected
    257   @retval EFI_STATUS            Error status returned by of gBS->LocateHandleBuffer().
    258 
    259 **/
    260 EFI_STATUS
    261 EFIAPI
    262 BdsLibDisconnectAllEfi (
    263   VOID
    264   )
    265 {
    266   EFI_STATUS  Status;
    267   UINTN       HandleCount;
    268   EFI_HANDLE  *HandleBuffer;
    269   UINTN       Index;
    270 
    271   //
    272   // Disconnect all
    273   //
    274   Status = gBS->LocateHandleBuffer (
    275                   AllHandles,
    276                   NULL,
    277                   NULL,
    278                   &HandleCount,
    279                   &HandleBuffer
    280                   );
    281   if (EFI_ERROR (Status)) {
    282     return Status;
    283   }
    284 
    285   for (Index = 0; Index < HandleCount; Index++) {
    286     Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
    287   }
    288 
    289   if (HandleBuffer != NULL) {
    290     FreePool (HandleBuffer);
    291   }
    292 
    293   return EFI_SUCCESS;
    294 }
    295 
    296 
    297 /**
    298   Connects all drivers to all controllers.
    299   This function make sure all the current system driver will manage
    300   the correspoinding controllers if have. And at the same time, make
    301   sure all the system controllers have driver to manage it if have.
    302 
    303 **/
    304 VOID
    305 EFIAPI
    306 BdsLibConnectAllDriversToAllControllers (
    307   VOID
    308   )
    309 {
    310   EFI_STATUS  Status;
    311 
    312   do {
    313     //
    314     // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
    315     //
    316     BdsLibConnectAllEfi ();
    317 
    318     //
    319     // Check to see if it's possible to dispatch an more DXE drivers.
    320     // The BdsLibConnectAllEfi () may have made new DXE drivers show up.
    321     // If anything is Dispatched Status == EFI_SUCCESS and we will try
    322     // the connect again.
    323     //
    324     Status = gDS->Dispatch ();
    325 
    326   } while (!EFI_ERROR (Status));
    327 
    328 }
    329 
    330 
    331 /**
    332   Connect the specific Usb device which match the short form device path,
    333   and whose bus is determined by Host Controller (Uhci or Ehci).
    334 
    335   @param  HostControllerPI      Uhci (0x00) or Ehci (0x20) or Both uhci and ehci
    336                                 (0xFF)
    337   @param  RemainingDevicePath   a short-form device path that starts with the first
    338                                 element  being a USB WWID or a USB Class device
    339                                 path
    340 
    341   @return EFI_INVALID_PARAMETER  RemainingDevicePath is NULL pointer.
    342                                  RemainingDevicePath is not a USB device path.
    343                                  Invalid HostControllerPI type.
    344   @return EFI_SUCCESS            Success to connect USB device
    345   @return EFI_NOT_FOUND          Fail to find handle for USB controller to connect.
    346 
    347 **/
    348 EFI_STATUS
    349 EFIAPI
    350 BdsLibConnectUsbDevByShortFormDP(
    351   IN UINT8                      HostControllerPI,
    352   IN EFI_DEVICE_PATH_PROTOCOL   *RemainingDevicePath
    353   )
    354 {
    355   EFI_STATUS                            Status;
    356   EFI_HANDLE                            *HandleArray;
    357   UINTN                                 HandleArrayCount;
    358   UINTN                                 Index;
    359   EFI_PCI_IO_PROTOCOL                   *PciIo;
    360   UINT8                                 Class[3];
    361   BOOLEAN                               AtLeastOneConnected;
    362 
    363   //
    364   // Check the passed in parameters
    365   //
    366   if (RemainingDevicePath == NULL) {
    367     return EFI_INVALID_PARAMETER;
    368   }
    369 
    370   if ((DevicePathType (RemainingDevicePath) != MESSAGING_DEVICE_PATH) ||
    371       ((DevicePathSubType (RemainingDevicePath) != MSG_USB_CLASS_DP)
    372       && (DevicePathSubType (RemainingDevicePath) != MSG_USB_WWID_DP)
    373       )) {
    374     return EFI_INVALID_PARAMETER;
    375   }
    376 
    377   if (HostControllerPI != 0xFF &&
    378       HostControllerPI != 0x00 &&
    379       HostControllerPI != 0x20) {
    380     return EFI_INVALID_PARAMETER;
    381   }
    382 
    383   //
    384   // Find the usb host controller firstly, then connect with the remaining device path
    385   //
    386   AtLeastOneConnected = FALSE;
    387   Status = gBS->LocateHandleBuffer (
    388                   ByProtocol,
    389                   &gEfiPciIoProtocolGuid,
    390                   NULL,
    391                   &HandleArrayCount,
    392                   &HandleArray
    393                   );
    394   if (!EFI_ERROR (Status)) {
    395     for (Index = 0; Index < HandleArrayCount; Index++) {
    396       Status = gBS->HandleProtocol (
    397                       HandleArray[Index],
    398                       &gEfiPciIoProtocolGuid,
    399                       (VOID **)&PciIo
    400                       );
    401       if (!EFI_ERROR (Status)) {
    402         //
    403         // Check whether the Pci device is the wanted usb host controller
    404         //
    405         Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
    406         if (!EFI_ERROR (Status)) {
    407           if ((PCI_CLASS_SERIAL == Class[2]) &&
    408               (PCI_CLASS_SERIAL_USB == Class[1])) {
    409             if (HostControllerPI == Class[0] || HostControllerPI == 0xFF) {
    410               Status = gBS->ConnectController (
    411                               HandleArray[Index],
    412                               NULL,
    413                               RemainingDevicePath,
    414                               FALSE
    415                               );
    416               if (!EFI_ERROR(Status)) {
    417                 AtLeastOneConnected = TRUE;
    418               }
    419             }
    420           }
    421         }
    422       }
    423     }
    424 
    425     if (HandleArray != NULL) {
    426       FreePool (HandleArray);
    427     }
    428 
    429     if (AtLeastOneConnected) {
    430       return EFI_SUCCESS;
    431     }
    432   }
    433 
    434   return EFI_NOT_FOUND;
    435 }
    436