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
BmConnectAllDriversToAllControllers(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
EfiBootManagerConnectAll(VOID)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
EfiBootManagerConnectDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * DevicePathToConnect,OUT EFI_HANDLE * MatchingHandle OPTIONAL)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
EfiBootManagerDisconnectAll(VOID)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
BmConnectUsbShortFormDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)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