]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c
ShellPkg: Connect all the consoles in "reconnect -r".
[mirror_edk2.git] / ShellPkg / Library / UefiShellDriver1CommandsLib / Connect.c
1 /** @file
2 Main file for connect shell Driver1 function.
3
4 Copyright (c) 2010 - 2014, 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 "UefiShellDriver1CommandsLib.h"
16
17 /**
18 Create all handles associate with every device path node.
19
20 @param DevicePathToConnect The device path which will be connected.
21
22 @retval EFI_SUCCESS All handles associate with every device path node
23 have been created.
24 @retval EFI_INVALID_PARAMETER DevicePathToConnect is NULL.
25 @retval EFI_NOT_FOUND Create the handle associate with one device path
26 node failed
27
28 **/
29 EFI_STATUS
30 ShellConnectDevicePath (
31 IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect
32 )
33 {
34 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
35 EFI_STATUS Status;
36 EFI_HANDLE Handle;
37 EFI_HANDLE PreviousHandle;
38
39 if (DevicePathToConnect == NULL) {
40 return EFI_INVALID_PARAMETER;
41 }
42
43 PreviousHandle = NULL;
44 do{
45 RemainingDevicePath = DevicePathToConnect;
46 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
47
48 if (!EFI_ERROR (Status) && (Handle != NULL)) {
49 if (PreviousHandle == Handle) {
50 Status = EFI_NOT_FOUND;
51 } else {
52 PreviousHandle = Handle;
53 Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
54 }
55 }
56
57 } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath) );
58
59 return Status;
60
61 }
62
63 /**
64 Connect drivers for PCI root bridge.
65
66 @retval EFI_SUCCESS Connect drivers successfully.
67 @retval EFI_NOT_FOUND Cannot find PCI root bridge device.
68
69 **/
70 EFI_STATUS
71 ShellConnectPciRootBridge (
72 VOID
73 )
74 {
75 UINTN RootBridgeHandleCount;
76 EFI_HANDLE *RootBridgeHandleBuffer;
77 UINTN RootBridgeIndex;
78 EFI_STATUS Status;
79
80 RootBridgeHandleCount = 0;
81
82 Status = gBS->LocateHandleBuffer (
83 ByProtocol,
84 &gEfiPciRootBridgeIoProtocolGuid,
85 NULL,
86 &RootBridgeHandleCount,
87 &RootBridgeHandleBuffer
88 );
89 if (EFI_ERROR (Status)) {
90 return Status;
91 }
92
93 for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
94 gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
95 }
96
97 FreePool (RootBridgeHandleBuffer);
98
99 return EFI_SUCCESS;
100 }
101
102
103 /**
104 Connect controller(s) and driver(s).
105
106 @param[in] ControllerHandle The handle to the controller. Should have driver binding on it.
107 @param[in] DriverHandle The handle to the driver. Should have driver binding.
108 @param[in] Recursive TRUE to connect recursively, FALSE otherwise.
109 @param[in] Output TRUE to have info on the screen, FALSE otherwise.
110 @param[in] AlwaysOutput Override Output for errors.
111
112 @retval EFI_SUCCESS The operation was successful.
113 **/
114 EFI_STATUS
115 EFIAPI
116 ConnectControllers (
117 IN CONST EFI_HANDLE ControllerHandle OPTIONAL,
118 IN CONST EFI_HANDLE DriverHandle OPTIONAL,
119 IN CONST BOOLEAN Recursive,
120 IN CONST BOOLEAN Output,
121 IN CONST BOOLEAN AlwaysOutput
122 )
123 {
124 EFI_STATUS Status;
125 EFI_STATUS Status2;
126 EFI_HANDLE *ControllerHandleList;
127 EFI_HANDLE *DriverHandleList;
128 EFI_HANDLE *HandleWalker;
129
130 ControllerHandleList = NULL;
131 Status = EFI_NOT_FOUND;
132 Status2 = EFI_NOT_FOUND;
133
134 //
135 // If we have a single handle to connect make that a 'list'
136 //
137 if (DriverHandle == NULL) {
138 DriverHandleList = NULL;
139 } else {
140 DriverHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE));
141 if (DriverHandleList == NULL) {
142 return (EFI_OUT_OF_RESOURCES);
143 }
144 DriverHandleList[0] = DriverHandle;
145 DriverHandleList[1] = NULL;
146 }
147
148 //
149 // do we connect all controllers (with a loop) or a single one...
150 // This is where we call the gBS->ConnectController function.
151 //
152 if (ControllerHandle == NULL) {
153 ControllerHandleList = GetHandleListByProtocol(&gEfiDevicePathProtocolGuid);
154 for (HandleWalker = ControllerHandleList
155 ; HandleWalker != NULL && *HandleWalker != NULL
156 ; HandleWalker++
157 ){
158 Status = gBS->ConnectController(*HandleWalker, DriverHandleList, NULL, Recursive);
159 if (!EFI_ERROR(Status)) {
160 Status2 = EFI_SUCCESS;
161 }
162 if ((Output && !EFI_ERROR(Status)) || AlwaysOutput) {
163 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Connect", ConvertHandleToHandleIndex(*HandleWalker), Status);
164 }
165 }
166 } else {
167 Status = gBS->ConnectController(ControllerHandle, DriverHandleList, NULL, Recursive);
168 if (!EFI_ERROR(Status)) {
169 Status2 = EFI_SUCCESS;
170 }
171 if ((Output && !EFI_ERROR(Status)) || AlwaysOutput) {
172 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Connect", ConvertHandleToHandleIndex(ControllerHandle), Status);
173 }
174 }
175
176 //
177 // Free any memory we allocated.
178 //
179 if (ControllerHandleList != NULL) {
180 FreePool(ControllerHandleList);
181 }
182 if (DriverHandleList != NULL) {
183 FreePool(DriverHandleList);
184 }
185 return (Status2);
186 }
187
188 /**
189 Do a connect from an EFI variable via it's key name.
190
191 @param[in] Key The name of the EFI Variable.
192
193 @retval EFI_SUCCESS The operation was successful.
194 **/
195 EFI_STATUS
196 EFIAPI
197 ShellConnectFromDevPaths (
198 IN CONST CHAR16 *Key
199 )
200 {
201 EFI_DEVICE_PATH_PROTOCOL *DevPath;
202 EFI_DEVICE_PATH_PROTOCOL *CopyOfDevPath;
203 EFI_DEVICE_PATH_PROTOCOL *Instance;
204 EFI_DEVICE_PATH_PROTOCOL *Next;
205 UINTN Length;
206 UINTN Index;
207 UINTN HandleArrayCount;
208 UINTN Size;
209 EFI_HANDLE *HandleArray;
210 EFI_STATUS Status;
211 BOOLEAN AtLeastOneConnected;
212 EFI_PCI_IO_PROTOCOL *PciIo;
213 UINT8 Class[3];
214
215 DevPath = NULL;
216 Length = 0;
217 AtLeastOneConnected = FALSE;
218
219 //
220 // Get the DevicePath buffer from the variable...
221 //
222 Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath);
223 if (Status == EFI_BUFFER_TOO_SMALL) {
224 DevPath = AllocateZeroPool(Length);
225 if (DevPath == NULL) {
226 return EFI_OUT_OF_RESOURCES;
227 }
228 Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath);
229 if (EFI_ERROR (Status)) {
230 if (DevPath != NULL) {
231 FreePool (DevPath);
232 }
233 return Status;
234 }
235 } else if (EFI_ERROR (Status)) {
236 return Status;
237 }
238
239 Status = EFI_NOT_FOUND;
240
241 CopyOfDevPath = DevPath;
242 //
243 // walk the list of devices and connect them
244 //
245 do {
246 //
247 // Check every instance of the console variable
248 //
249 Instance = GetNextDevicePathInstance (&CopyOfDevPath, &Size);
250 if (Instance == NULL) {
251 if (DevPath != NULL) {
252 FreePool (DevPath);
253 }
254 return EFI_UNSUPPORTED;
255 }
256
257 Next = Instance;
258 while (!IsDevicePathEndType (Next)) {
259 Next = NextDevicePathNode (Next);
260 }
261
262 SetDevicePathEndNode (Next);
263 //
264 // connect short form device path
265 //
266 if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
267 ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP)
268 || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)
269 )) {
270
271 Status = ShellConnectPciRootBridge ();
272 if (EFI_ERROR(Status)) {
273 FreePool(Instance);
274 FreePool(DevPath);
275 return Status;
276 }
277
278 Status = gBS->LocateHandleBuffer (
279 ByProtocol,
280 &gEfiPciIoProtocolGuid,
281 NULL,
282 &HandleArrayCount,
283 &HandleArray
284 );
285
286 if (!EFI_ERROR (Status)) {
287 for (Index = 0; Index < HandleArrayCount; Index++) {
288 Status = gBS->HandleProtocol (
289 HandleArray[Index],
290 &gEfiPciIoProtocolGuid,
291 (VOID **)&PciIo
292 );
293
294 if (!EFI_ERROR (Status)) {
295 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
296 if (!EFI_ERROR (Status)) {
297 if ((PCI_CLASS_SERIAL == Class[2]) &&
298 (PCI_CLASS_SERIAL_USB == Class[1])) {
299 Status = gBS->ConnectController (
300 HandleArray[Index],
301 NULL,
302 Instance,
303 FALSE
304 );
305 if (!EFI_ERROR(Status)) {
306 AtLeastOneConnected = TRUE;
307 }
308 }
309 }
310 }
311 }
312 }
313
314 if (HandleArray != NULL) {
315 FreePool (HandleArray);
316 }
317 } else {
318 //
319 // connect the entire device path
320 //
321 Status = ShellConnectDevicePath (Instance);
322 if (!EFI_ERROR (Status)) {
323 AtLeastOneConnected = TRUE;
324 }
325 }
326 FreePool (Instance);
327
328 } while (CopyOfDevPath != NULL);
329
330 if (DevPath != NULL) {
331 FreePool(DevPath);
332 }
333
334 if (AtLeastOneConnected) {
335 return EFI_SUCCESS;
336 } else {
337 return EFI_NOT_FOUND;
338 }
339
340 }
341
342 /**
343 Convert the handle identifiers from strings and then connect them.
344
345 One of them should have driver binding and either can be NULL.
346
347 @param[in] Handle1 The first handle.
348 @param[in] Handle2 The second handle.
349 @param[in] Recursive TRUE to do connect recursively. FALSE otherwise.
350 @param[in] Output TRUE to have output to screen. FALSE otherwise.
351
352 @retval EFI_SUCCESS The operation was successful.
353 **/
354 EFI_STATUS
355 EFIAPI
356 ConvertAndConnectControllers (
357 IN EFI_HANDLE *Handle1 OPTIONAL,
358 IN EFI_HANDLE *Handle2 OPTIONAL,
359 IN CONST BOOLEAN Recursive,
360 IN CONST BOOLEAN Output
361 )
362 {
363 //
364 // if only one is NULL verify it's the proper one...
365 //
366 if ( (Handle1 == NULL && Handle2 != NULL)
367 || (Handle1 != NULL && Handle2 == NULL)
368 ){
369 //
370 // Figure out which one should be NULL and move the handle to the right place.
371 // If Handle1 is NULL then test Handle2 and vise versa.
372 // The one that DOES has driver binding must be Handle2
373 //
374 if (Handle1 == NULL) {
375 if (EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
376 // swap
377 Handle1 = Handle2;
378 Handle2 = NULL;
379 } else {
380 // We're all good...
381 }
382 } else {
383 if (EFI_ERROR(gBS->OpenProtocol(Handle1, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
384 // We're all good...
385 } else {
386 // swap
387 Handle2 = Handle1;
388 Handle1 = NULL;
389 }
390 }
391 }
392
393 return (ConnectControllers(Handle1, Handle2, Recursive, Output, (BOOLEAN)(Handle2 != NULL && Handle1 != NULL)));
394 }
395
396 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
397 {L"-c", TypeFlag},
398 {L"-r", TypeFlag},
399 {NULL, TypeMax}
400 };
401
402 /**
403 Function for 'connect' command.
404
405 @param[in] ImageHandle Handle to the Image (NULL if Internal).
406 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
407 **/
408 SHELL_STATUS
409 EFIAPI
410 ShellCommandRunConnect (
411 IN EFI_HANDLE ImageHandle,
412 IN EFI_SYSTEM_TABLE *SystemTable
413 )
414 {
415 EFI_STATUS Status;
416 LIST_ENTRY *Package;
417 CHAR16 *ProblemParam;
418 SHELL_STATUS ShellStatus;
419 CONST CHAR16 *Param1;
420 CONST CHAR16 *Param2;
421 UINTN Count;
422 EFI_HANDLE Handle1;
423 EFI_HANDLE Handle2;
424 UINT64 Intermediate;
425
426 ShellStatus = SHELL_SUCCESS;
427 //
428 // initialize the shell lib (we must be in non-auto-init...)
429 //
430 Status = ShellInitialize();
431 ASSERT_EFI_ERROR(Status);
432
433 Status = CommandInit();
434 ASSERT_EFI_ERROR(Status);
435
436 //
437 // parse the command line
438 //
439 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
440 if (EFI_ERROR(Status)) {
441 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
442 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, ProblemParam);
443 FreePool(ProblemParam);
444 ShellStatus = SHELL_INVALID_PARAMETER;
445 } else {
446 ASSERT(FALSE);
447 }
448 } else {
449 //
450 // if more than 2 'value' parameters (plus the name one) or either -r or -c with any value parameters we have too many parameters
451 //
452 Count = (gInReconnect?0x4:0x3);
453 if ((ShellCommandLineGetCount(Package) > Count)
454 ||((ShellCommandLineGetFlag(Package, L"-r") || ShellCommandLineGetFlag(Package, L"-c")) && ShellCommandLineGetCount(Package)>1)
455 ||(ShellCommandLineGetFlag(Package, L"-r") && ShellCommandLineGetFlag(Package, L"-c") )
456 ){
457 //
458 // error for too many parameters
459 //
460 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle);
461 ShellStatus = SHELL_INVALID_PARAMETER;
462 } else if (ShellCommandLineGetFlag(Package, L"-c")) {
463 //
464 // do the conin and conout from EFI variables
465 // if the first fails dont 'loose' the error
466 //
467 Status = ShellConnectFromDevPaths(L"ConInDev");
468 if (EFI_ERROR(Status)) {
469 ShellConnectFromDevPaths(L"ConOutDev");
470 } else {
471 Status = ShellConnectFromDevPaths(L"ConOutDev");
472 }
473 if (EFI_ERROR(Status)) {
474 ShellConnectFromDevPaths(L"ErrOutDev");
475 } else {
476 Status = ShellConnectFromDevPaths(L"ErrOutDev");
477 }
478 if (EFI_ERROR(Status)) {
479 ShellConnectFromDevPaths(L"ErrOut");
480 } else {
481 Status = ShellConnectFromDevPaths(L"ErrOut");
482 }
483 if (EFI_ERROR(Status)) {
484 ShellConnectFromDevPaths(L"ConIn");
485 } else {
486 Status = ShellConnectFromDevPaths(L"ConIn");
487 }
488 if (EFI_ERROR(Status)) {
489 ShellConnectFromDevPaths(L"ConOut");
490 } else {
491 Status = ShellConnectFromDevPaths(L"ConOut");
492 }
493 if (EFI_ERROR(Status)) {
494 ShellStatus = SHELL_DEVICE_ERROR;
495 }
496 } else {
497 //
498 // 0, 1, or 2 specific handles and possibly recursive
499 //
500 Param1 = ShellCommandLineGetRawValue(Package, 1);
501 Param2 = ShellCommandLineGetRawValue(Package, 2);
502 Count = ShellCommandLineGetCount(Package);
503
504 if (Param1 != NULL) {
505 Status = ShellConvertStringToUint64(Param1, &Intermediate, TRUE, FALSE);
506 Handle1 = ConvertHandleIndexToHandle((UINTN)Intermediate);
507 if (EFI_ERROR(Status)) {
508 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, Param1);
509 ShellStatus = SHELL_INVALID_PARAMETER;
510 }
511 } else {
512 Handle1 = NULL;
513 }
514
515 if (Param2 != NULL) {
516 Status = ShellConvertStringToUint64(Param2, &Intermediate, TRUE, FALSE);
517 Handle2 = ConvertHandleIndexToHandle((UINTN)Intermediate);
518 if (EFI_ERROR(Status)) {
519 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, Param2);
520 ShellStatus = SHELL_INVALID_PARAMETER;
521 }
522 } else {
523 Handle2 = NULL;
524 }
525
526 if (ShellStatus == SHELL_SUCCESS) {
527 if (Param1 != NULL && Handle1 == NULL){
528 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, Param1);
529 ShellStatus = SHELL_INVALID_PARAMETER;
530 } else if (Param2 != NULL && Handle2 == NULL) {
531 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, Param2);
532 ShellStatus = SHELL_INVALID_PARAMETER;
533 } else if (Handle2 != NULL && Handle1 != NULL && EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
534 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, Param2);
535 ShellStatus = SHELL_INVALID_PARAMETER;
536 } else {
537 Status = ConvertAndConnectControllers(Handle1, Handle2, ShellCommandLineGetFlag(Package, L"-r"), (BOOLEAN)(Count!=0));
538 if (EFI_ERROR(Status)) {
539 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CONNECT_NONE), gShellDriver1HiiHandle);
540 ShellStatus = SHELL_DEVICE_ERROR;
541 }
542 }
543 }
544 }
545
546 ShellCommandLineFreeVarList (Package);
547 }
548 return (ShellStatus);
549 }
550