]>
Commit | Line | Data |
---|---|---|
1d112229 RN |
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 | ||
111 | **/ | |
112 | EFI_STATUS | |
113 | EFIAPI | |
114 | EfiBootManagerConnectDevicePath ( | |
115 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect, | |
116 | OUT EFI_HANDLE *MatchingHandle OPTIONAL | |
117 | ) | |
118 | { | |
119 | EFI_STATUS Status; | |
120 | EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; | |
121 | EFI_HANDLE Handle; | |
122 | EFI_HANDLE PreviousHandle; | |
123 | EFI_TPL CurrentTpl; | |
124 | ||
125 | if (DevicePathToConnect == NULL) { | |
126 | return EFI_INVALID_PARAMETER; | |
127 | } | |
128 | ||
129 | CurrentTpl = EfiGetCurrentTpl (); | |
130 | // | |
131 | // Start the real work of connect with RemainingDevicePath | |
132 | // | |
133 | PreviousHandle = NULL; | |
134 | do { | |
135 | // | |
136 | // Find the handle that best matches the Device Path. If it is only a | |
137 | // partial match the remaining part of the device path is returned in | |
138 | // RemainingDevicePath. | |
139 | // | |
140 | RemainingDevicePath = DevicePathToConnect; | |
141 | Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle); | |
142 | if (!EFI_ERROR (Status)) { | |
143 | if (Handle == PreviousHandle) { | |
144 | // | |
145 | // If no forward progress is made try invoking the Dispatcher. | |
146 | // A new FV may have been added to the system an new drivers | |
147 | // may now be found. | |
148 | // Status == EFI_SUCCESS means a driver was dispatched | |
149 | // Status == EFI_NOT_FOUND means no new drivers were dispatched | |
150 | // | |
151 | if (CurrentTpl == TPL_APPLICATION) { | |
152 | Status = gDS->Dispatch (); | |
153 | } else { | |
154 | // | |
155 | // Always return EFI_NOT_FOUND here | |
156 | // to prevent dead loop when control handle is found but connection failded case | |
157 | // | |
158 | Status = EFI_NOT_FOUND; | |
159 | } | |
160 | } | |
161 | ||
162 | ||
163 | if (!EFI_ERROR (Status)) { | |
164 | PreviousHandle = Handle; | |
165 | // | |
166 | // Connect all drivers that apply to Handle and RemainingDevicePath, | |
167 | // the Recursive flag is FALSE so only one level will be expanded. | |
168 | // | |
169 | // Do not check the connect status here, if the connect controller fail, | |
170 | // then still give the chance to do dispatch, because partial | |
171 | // 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 | gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE); | |
181 | if (MatchingHandle != NULL) { | |
182 | *MatchingHandle = Handle; | |
183 | } | |
184 | } | |
185 | } | |
186 | // | |
187 | // Loop until RemainingDevicePath is an empty device path | |
188 | // | |
189 | } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath)); | |
190 | ||
191 | ASSERT (EFI_ERROR (Status) || IsDevicePathEnd (RemainingDevicePath)); | |
192 | ||
193 | return Status; | |
194 | } | |
195 | ||
196 | /** | |
197 | This function will disconnect all current system handles. | |
198 | ||
199 | gBS->DisconnectController() is invoked for each handle exists in system handle buffer. | |
200 | If handle is a bus type handle, all childrens also are disconnected recursively by | |
201 | gBS->DisconnectController(). | |
202 | **/ | |
203 | VOID | |
204 | EFIAPI | |
205 | EfiBootManagerDisconnectAll ( | |
206 | VOID | |
207 | ) | |
208 | { | |
209 | UINTN HandleCount; | |
210 | EFI_HANDLE *HandleBuffer; | |
211 | UINTN Index; | |
212 | ||
213 | // | |
214 | // Disconnect all | |
215 | // | |
216 | gBS->LocateHandleBuffer ( | |
217 | AllHandles, | |
218 | NULL, | |
219 | NULL, | |
220 | &HandleCount, | |
221 | &HandleBuffer | |
222 | ); | |
223 | for (Index = 0; Index < HandleCount; Index++) { | |
224 | gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); | |
225 | } | |
226 | ||
227 | if (HandleBuffer != NULL) { | |
228 | FreePool (HandleBuffer); | |
229 | } | |
230 | } | |
231 | ||
232 | /** | |
233 | Connect the specific Usb device which match the short form device path, | |
234 | and whose bus is determined by Host Controller (Uhci or Ehci). | |
235 | ||
236 | @param DevicePath A short-form device path that starts with the first | |
237 | element being a USB WWID or a USB Class device | |
238 | path | |
239 | ||
240 | @return EFI_INVALID_PARAMETER DevicePath is NULL pointer. | |
241 | DevicePath is not a USB device path. | |
242 | ||
243 | @return EFI_SUCCESS Success to connect USB device | |
244 | @return EFI_NOT_FOUND Fail to find handle for USB controller to connect. | |
245 | ||
246 | **/ | |
247 | EFI_STATUS | |
248 | BmConnectUsbShortFormDevicePath ( | |
249 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
250 | ) | |
251 | { | |
252 | EFI_STATUS Status; | |
253 | EFI_HANDLE *Handles; | |
254 | UINTN HandleCount; | |
255 | UINTN Index; | |
256 | EFI_PCI_IO_PROTOCOL *PciIo; | |
257 | UINT8 Class[3]; | |
258 | BOOLEAN AtLeastOneConnected; | |
259 | ||
260 | // | |
261 | // Check the passed in parameters | |
262 | // | |
263 | if (DevicePath == NULL) { | |
264 | return EFI_INVALID_PARAMETER; | |
265 | } | |
266 | ||
267 | if ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) || | |
268 | ((DevicePathSubType (DevicePath) != MSG_USB_CLASS_DP) && (DevicePathSubType (DevicePath) != MSG_USB_WWID_DP)) | |
269 | ) { | |
270 | return EFI_INVALID_PARAMETER; | |
271 | } | |
272 | ||
273 | // | |
274 | // Find the usb host controller firstly, then connect with the remaining device path | |
275 | // | |
276 | AtLeastOneConnected = FALSE; | |
277 | Status = gBS->LocateHandleBuffer ( | |
278 | ByProtocol, | |
279 | &gEfiPciIoProtocolGuid, | |
280 | NULL, | |
281 | &HandleCount, | |
282 | &Handles | |
283 | ); | |
284 | if (!EFI_ERROR (Status)) { | |
285 | for (Index = 0; Index < HandleCount; Index++) { | |
286 | Status = gBS->HandleProtocol ( | |
287 | Handles[Index], | |
288 | &gEfiPciIoProtocolGuid, | |
289 | (VOID **) &PciIo | |
290 | ); | |
291 | if (!EFI_ERROR (Status)) { | |
292 | // | |
293 | // Check whether the Pci device is the wanted usb host controller | |
294 | // | |
295 | Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class); | |
296 | if (!EFI_ERROR (Status) && | |
297 | ((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1])) | |
298 | ) { | |
299 | Status = gBS->ConnectController ( | |
300 | Handles[Index], | |
301 | NULL, | |
302 | DevicePath, | |
303 | FALSE | |
304 | ); | |
305 | if (!EFI_ERROR(Status)) { | |
306 | AtLeastOneConnected = TRUE; | |
307 | } | |
308 | } | |
309 | } | |
310 | } | |
311 | ||
312 | if (Handles != NULL) { | |
313 | FreePool (Handles); | |
314 | } | |
315 | } | |
316 | ||
317 | return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND; | |
318 | } |