1 /** @file
2   Console Platform DXE Driver, install Console Device Guids and update Console
3   Environment Variables.
4 
5 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "ConPlatform.h"
17 
18 
19 EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextInDriverBinding = {
20   ConPlatformTextInDriverBindingSupported,
21   ConPlatformTextInDriverBindingStart,
22   ConPlatformTextInDriverBindingStop,
23   0xa,
24   NULL,
25   NULL
26 };
27 
28 EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextOutDriverBinding = {
29   ConPlatformTextOutDriverBindingSupported,
30   ConPlatformTextOutDriverBindingStart,
31   ConPlatformTextOutDriverBindingStop,
32   0xa,
33   NULL,
34   NULL
35 };
36 
37 /**
38   Entrypoint of this module.
39 
40   This function is the entrypoint of this module. It installs Driver Binding
41   Protocols together with Component Name Protocols.
42 
43   @param  ImageHandle       The firmware allocated handle for the EFI image.
44   @param  SystemTable       A pointer to the EFI System Table.
45 
46   @retval EFI_SUCCESS       The entry point is executed successfully.
47 
48 **/
49 EFI_STATUS
50 EFIAPI
InitializeConPlatform(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)51 InitializeConPlatform(
52   IN EFI_HANDLE           ImageHandle,
53   IN EFI_SYSTEM_TABLE     *SystemTable
54   )
55 {
56   EFI_STATUS              Status;
57 
58   Status = EfiLibInstallDriverBindingComponentName2 (
59              ImageHandle,
60              SystemTable,
61              &gConPlatformTextInDriverBinding,
62              ImageHandle,
63              &gConPlatformComponentName,
64              &gConPlatformComponentName2
65              );
66   ASSERT_EFI_ERROR (Status);
67 
68   Status = EfiLibInstallDriverBindingComponentName2 (
69              ImageHandle,
70              SystemTable,
71              &gConPlatformTextOutDriverBinding,
72              NULL,
73              &gConPlatformComponentName,
74              &gConPlatformComponentName2
75              );
76   ASSERT_EFI_ERROR (Status);
77 
78   return EFI_SUCCESS;
79 }
80 
81 
82 /**
83   Test to see if EFI_SIMPLE_TEXT_INPUT_PROTOCOL is supported on ControllerHandle.
84 
85   @param  This                Protocol instance pointer.
86   @param  ControllerHandle    Handle of device to test.
87   @param  RemainingDevicePath Optional parameter use to pick a specific child
88                               device to start.
89 
90   @retval EFI_SUCCESS         This driver supports this device.
91   @retval other               This driver does not support this device.
92 
93 **/
94 EFI_STATUS
95 EFIAPI
ConPlatformTextInDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)96 ConPlatformTextInDriverBindingSupported (
97   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
98   IN  EFI_HANDLE                   ControllerHandle,
99   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
100   )
101 {
102   return ConPlatformDriverBindingSupported (
103            This,
104            ControllerHandle,
105            &gEfiSimpleTextInProtocolGuid
106            );
107 }
108 
109 
110 /**
111   Test to see if EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL is supported on ControllerHandle.
112 
113   @param  This                Protocol instance pointer.
114   @param  ControllerHandle    Handle of device to test.
115   @param  RemainingDevicePath Optional parameter use to pick a specific child
116                               device to start.
117 
118   @retval EFI_SUCCESS         This driver supports this device.
119   @retval other               This driver does not support this device.
120 
121 **/
122 EFI_STATUS
123 EFIAPI
ConPlatformTextOutDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)124 ConPlatformTextOutDriverBindingSupported (
125   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
126   IN  EFI_HANDLE                   ControllerHandle,
127   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
128   )
129 {
130   return ConPlatformDriverBindingSupported (
131            This,
132            ControllerHandle,
133            &gEfiSimpleTextOutProtocolGuid
134            );
135 }
136 
137 
138 /**
139   Test to see if the specified protocol is supported on ControllerHandle.
140 
141   @param  This                Protocol instance pointer.
142   @param  ControllerHandle    Handle of device to test.
143   @param  ProtocolGuid        The specfic protocol.
144 
145   @retval EFI_SUCCESS         This driver supports this device.
146   @retval other               This driver does not support this device.
147 
148 **/
149 EFI_STATUS
ConPlatformDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_GUID * ProtocolGuid)150 ConPlatformDriverBindingSupported (
151   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
152   IN  EFI_HANDLE                   ControllerHandle,
153   IN  EFI_GUID                     *ProtocolGuid
154   )
155 {
156   EFI_STATUS  Status;
157   VOID        *Interface;
158 
159   //
160   // Test to see if this is a physical device by checking if
161   // it has a Device Path Protocol.
162   //
163   Status = gBS->OpenProtocol (
164                   ControllerHandle,
165                   &gEfiDevicePathProtocolGuid,
166                   NULL,
167                   This->DriverBindingHandle,
168                   ControllerHandle,
169                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
170                   );
171   if (EFI_ERROR (Status)) {
172     return Status;
173   }
174   //
175   // Test to see if this device supports the specified Protocol.
176   //
177   Status = gBS->OpenProtocol (
178                   ControllerHandle,
179                   ProtocolGuid,
180                   (VOID **) &Interface,
181                   This->DriverBindingHandle,
182                   ControllerHandle,
183                   EFI_OPEN_PROTOCOL_BY_DRIVER
184                   );
185   if (EFI_ERROR (Status)) {
186     return Status;
187   }
188 
189   gBS->CloseProtocol (
190          ControllerHandle,
191          ProtocolGuid,
192          This->DriverBindingHandle,
193          ControllerHandle
194          );
195 
196   return EFI_SUCCESS;
197 }
198 
199 /**
200   Start this driver on the device for console input.
201 
202   Start this driver on ControllerHandle by opening Simple Text Input Protocol,
203   reading Device Path, and installing Console In Devcice GUID on ControllerHandle.
204 
205   If this devcie is not one hot-plug devce, append its device path into the
206   console environment variables ConInDev.
207 
208   @param  This                 Protocol instance pointer.
209   @param  ControllerHandle     Handle of device to bind driver to
210   @param  RemainingDevicePath  Optional parameter use to pick a specific child
211                                device to start.
212 
213   @retval EFI_SUCCESS          This driver is added to ControllerHandle
214   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
215   @retval other                This driver does not support this device.
216 
217 **/
218 EFI_STATUS
219 EFIAPI
ConPlatformTextInDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)220 ConPlatformTextInDriverBindingStart (
221   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
222   IN  EFI_HANDLE                    ControllerHandle,
223   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
224   )
225 {
226   EFI_STATUS                     Status;
227   EFI_DEVICE_PATH_PROTOCOL       *DevicePath;
228   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;
229   BOOLEAN                        IsInConInVariable;
230 
231   //
232   // Get the Device Path Protocol so the environment variables can be updated
233   //
234   Status = gBS->OpenProtocol (
235                   ControllerHandle,
236                   &gEfiDevicePathProtocolGuid,
237                   (VOID **) &DevicePath,
238                   This->DriverBindingHandle,
239                   ControllerHandle,
240                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
241                   );
242   if (EFI_ERROR (Status)) {
243     return Status;
244   }
245   //
246   // Open the Simple Text Input Protocol BY_DRIVER
247   //
248   Status = gBS->OpenProtocol (
249                   ControllerHandle,
250                   &gEfiSimpleTextInProtocolGuid,
251                   (VOID **) &TextIn,
252                   This->DriverBindingHandle,
253                   ControllerHandle,
254                   EFI_OPEN_PROTOCOL_BY_DRIVER
255                   );
256   if (EFI_ERROR (Status)) {
257     return Status;
258   }
259   //
260   // Check if the device path is in ConIn Variable
261   //
262   IsInConInVariable = FALSE;
263   Status = ConPlatformUpdateDeviceVariable (
264              L"ConIn",
265              DevicePath,
266              Check
267              );
268   if (!EFI_ERROR (Status)) {
269     IsInConInVariable = TRUE;
270   }
271 
272   //
273   // Check the device path, if it is a hot plug device,
274   // do not put the device path into ConInDev, and install
275   // gEfiConsoleInDeviceGuid to the device handle directly.
276   // The policy is, make hot plug device plug in and play immediately.
277   //
278   if (IsHotPlugDevice (DevicePath)) {
279     gBS->InstallMultipleProtocolInterfaces (
280            &ControllerHandle,
281            &gEfiConsoleInDeviceGuid,
282            NULL,
283            NULL
284            );
285     //
286     // Append the device path to ConInDev only if it is in ConIn variable.
287     //
288     if (IsInConInVariable) {
289       ConPlatformUpdateDeviceVariable (
290         L"ConInDev",
291         DevicePath,
292         Append
293         );
294     }
295   } else {
296     //
297     // If it is not a hot-plug device, append the device path to the
298     // ConInDev environment variable
299     //
300     ConPlatformUpdateDeviceVariable (
301       L"ConInDev",
302       DevicePath,
303       Append
304       );
305 
306     //
307     // If the device path is an instance in the ConIn environment variable,
308     // then install EfiConsoleInDeviceGuid onto ControllerHandle
309     //
310     if (IsInConInVariable) {
311       gBS->InstallMultipleProtocolInterfaces (
312              &ControllerHandle,
313              &gEfiConsoleInDeviceGuid,
314              NULL,
315              NULL
316              );
317     } else {
318       gBS->CloseProtocol (
319              ControllerHandle,
320              &gEfiSimpleTextInProtocolGuid,
321              This->DriverBindingHandle,
322              ControllerHandle
323              );
324     }
325   }
326 
327   return EFI_SUCCESS;
328 }
329 
330 /**
331   Start this driver on the device for console output and stardard error output.
332 
333   Start this driver on ControllerHandle by opening Simple Text Output Protocol,
334   reading Device Path, and installing Console Out Devcic GUID, Standard Error
335   Device GUID on ControllerHandle.
336 
337   If this devcie is not one hot-plug devce, append its device path into the
338   console environment variables ConOutDev, ErrOutDev.
339 
340   @param  This                 Protocol instance pointer.
341   @param  ControllerHandle     Handle of device to bind driver to
342   @param  RemainingDevicePath  Optional parameter use to pick a specific child
343                                device to start.
344 
345   @retval EFI_SUCCESS          This driver is added to ControllerHandle
346   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
347   @retval other                This driver does not support this device
348 
349 **/
350 EFI_STATUS
351 EFIAPI
ConPlatformTextOutDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)352 ConPlatformTextOutDriverBindingStart (
353   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
354   IN  EFI_HANDLE                    ControllerHandle,
355   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
356   )
357 {
358   EFI_STATUS                       Status;
359   EFI_DEVICE_PATH_PROTOCOL         *DevicePath;
360   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;
361   BOOLEAN                          NeedClose;
362   BOOLEAN                          IsInConOutVariable;
363   BOOLEAN                          IsInErrOutVariable;
364 
365   NeedClose = TRUE;
366 
367   //
368   // Get the Device Path Protocol so the environment variables can be updated
369   //
370   Status = gBS->OpenProtocol (
371                   ControllerHandle,
372                   &gEfiDevicePathProtocolGuid,
373                   (VOID **) &DevicePath,
374                   This->DriverBindingHandle,
375                   ControllerHandle,
376                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
377                   );
378   if (EFI_ERROR (Status)) {
379     return Status;
380   }
381   //
382   // Open the Simple Text Output Protocol BY_DRIVER
383   //
384   Status = gBS->OpenProtocol (
385                   ControllerHandle,
386                   &gEfiSimpleTextOutProtocolGuid,
387                   (VOID **) &TextOut,
388                   This->DriverBindingHandle,
389                   ControllerHandle,
390                   EFI_OPEN_PROTOCOL_BY_DRIVER
391                   );
392   if (EFI_ERROR (Status)) {
393     return Status;
394   }
395   //
396   // Check if the device path is in ConOut & ErrOut Variable
397   //
398   IsInConOutVariable = FALSE;
399   Status = ConPlatformUpdateDeviceVariable (
400              L"ConOut",
401              DevicePath,
402              Check
403              );
404   if (!EFI_ERROR (Status)) {
405     IsInConOutVariable = TRUE;
406   }
407 
408   IsInErrOutVariable = FALSE;
409   Status = ConPlatformUpdateDeviceVariable (
410              L"ErrOut",
411              DevicePath,
412              Check
413              );
414   if (!EFI_ERROR (Status)) {
415     IsInErrOutVariable = TRUE;
416   }
417 
418   //
419   // Check the device path, if it is a hot plug device,
420   // do not put the device path into ConOutDev and ErrOutDev,
421   // and install gEfiConsoleOutDeviceGuid to the device handle directly.
422   // The policy is, make hot plug device plug in and play immediately.
423   //
424   if (IsHotPlugDevice (DevicePath)) {
425     gBS->InstallMultipleProtocolInterfaces (
426            &ControllerHandle,
427            &gEfiConsoleOutDeviceGuid,
428            NULL,
429            NULL
430            );
431     //
432     // Append the device path to ConOutDev only if it is in ConOut variable.
433     //
434     if (IsInConOutVariable) {
435       ConPlatformUpdateDeviceVariable (
436         L"ConOutDev",
437         DevicePath,
438         Append
439         );
440     }
441     //
442     // Append the device path to ErrOutDev only if it is in ErrOut variable.
443     //
444     if (IsInErrOutVariable) {
445       ConPlatformUpdateDeviceVariable (
446         L"ErrOutDev",
447         DevicePath,
448         Append
449         );
450     }
451   } else {
452     //
453     // If it is not a hot-plug device, append the device path to
454     // the ConOutDev and ErrOutDev environment variable.
455     // For GOP device path, append the sibling device path as well.
456     //
457     if (!ConPlatformUpdateGopCandidate (DevicePath)) {
458       ConPlatformUpdateDeviceVariable (
459         L"ConOutDev",
460         DevicePath,
461         Append
462         );
463       //
464       // Then append the device path to the ErrOutDev environment variable
465       //
466       ConPlatformUpdateDeviceVariable (
467         L"ErrOutDev",
468         DevicePath,
469         Append
470         );
471     }
472 
473     //
474     // If the device path is an instance in the ConOut environment variable,
475     // then install EfiConsoleOutDeviceGuid onto ControllerHandle
476     //
477     if (IsInConOutVariable) {
478       NeedClose = FALSE;
479       Status = gBS->InstallMultipleProtocolInterfaces (
480                       &ControllerHandle,
481                       &gEfiConsoleOutDeviceGuid,
482                       NULL,
483                       NULL
484                       );
485     }
486     //
487     // If the device path is an instance in the ErrOut environment variable,
488     // then install EfiStandardErrorDeviceGuid onto ControllerHandle
489     //
490     if (IsInErrOutVariable) {
491       NeedClose = FALSE;
492       gBS->InstallMultipleProtocolInterfaces (
493              &ControllerHandle,
494              &gEfiStandardErrorDeviceGuid,
495              NULL,
496              NULL
497              );
498     }
499 
500     if (NeedClose) {
501       gBS->CloseProtocol (
502              ControllerHandle,
503              &gEfiSimpleTextOutProtocolGuid,
504              This->DriverBindingHandle,
505              ControllerHandle
506              );
507     }
508   }
509 
510   return EFI_SUCCESS;
511 }
512 
513 /**
514   Stop this driver on ControllerHandle by removing Console In Devcice GUID
515   and closing the Simple Text Input protocol on ControllerHandle.
516 
517   @param  This              Protocol instance pointer.
518   @param  ControllerHandle  Handle of device to stop driver on
519   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
520                             children is zero stop the entire bus driver.
521   @param  ChildHandleBuffer List of Child Handles to Stop.
522 
523   @retval EFI_SUCCESS       This driver is removed ControllerHandle
524   @retval other             This driver was not removed from this device
525 
526 **/
527 EFI_STATUS
528 EFIAPI
ConPlatformTextInDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)529 ConPlatformTextInDriverBindingStop (
530   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
531   IN  EFI_HANDLE                   ControllerHandle,
532   IN  UINTN                        NumberOfChildren,
533   IN  EFI_HANDLE                   *ChildHandleBuffer
534   )
535 {
536   EFI_STATUS                Status;
537   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
538 
539   //
540   // Get the Device Path Protocol firstly
541   //
542   Status = gBS->OpenProtocol (
543                   ControllerHandle,
544                   &gEfiDevicePathProtocolGuid,
545                   (VOID **) &DevicePath,
546                   This->DriverBindingHandle,
547                   ControllerHandle,
548                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
549                   );
550   //
551   // If there is device path on ControllerHandle
552   //
553   if (!EFI_ERROR (Status)) {
554     //
555     // Remove DevicePath from ConInDev if exists.
556     //
557     ConPlatformUpdateDeviceVariable (
558       L"ConInDev",
559       DevicePath,
560       Delete
561       );
562   }
563 
564   //
565   // Uninstall the Console Device GUIDs from Controller Handle
566   //
567   ConPlatformUnInstallProtocol (
568     This,
569     ControllerHandle,
570     &gEfiConsoleInDeviceGuid
571     );
572 
573   //
574   // Close the Simple Text Input Protocol
575   //
576   gBS->CloseProtocol (
577          ControllerHandle,
578          &gEfiSimpleTextInProtocolGuid,
579          This->DriverBindingHandle,
580          ControllerHandle
581          );
582 
583   return EFI_SUCCESS;
584 }
585 
586 
587 /**
588   Stop this driver on ControllerHandle by removing Console Out Devcice GUID
589   and closing the Simple Text Output protocol on ControllerHandle.
590 
591   @param  This              Protocol instance pointer.
592   @param  ControllerHandle  Handle of device to stop driver on
593   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
594                             children is zero stop the entire bus driver.
595   @param  ChildHandleBuffer List of Child Handles to Stop.
596 
597   @retval EFI_SUCCESS       This driver is removed ControllerHandle
598   @retval other             This driver was not removed from this device
599 
600 **/
601 EFI_STATUS
602 EFIAPI
ConPlatformTextOutDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)603 ConPlatformTextOutDriverBindingStop (
604   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
605   IN  EFI_HANDLE                   ControllerHandle,
606   IN  UINTN                        NumberOfChildren,
607   IN  EFI_HANDLE                   *ChildHandleBuffer
608   )
609 {
610   EFI_STATUS                Status;
611   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
612 
613   //
614   // Get the Device Path Protocol firstly
615   //
616   Status = gBS->OpenProtocol (
617                   ControllerHandle,
618                   &gEfiDevicePathProtocolGuid,
619                   (VOID **) &DevicePath,
620                   This->DriverBindingHandle,
621                   ControllerHandle,
622                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
623                   );
624   if (!EFI_ERROR (Status)) {
625     //
626     // Remove DevicePath from ConOutDev and ErrOutDev if exists.
627     //
628     ConPlatformUpdateDeviceVariable (
629       L"ConOutDev",
630       DevicePath,
631       Delete
632       );
633     ConPlatformUpdateDeviceVariable (
634       L"ErrOutDev",
635       DevicePath,
636       Delete
637       );
638   }
639 
640   //
641   // Uninstall the Console Device GUIDs from Controller Handle
642   //
643   ConPlatformUnInstallProtocol (
644     This,
645     ControllerHandle,
646     &gEfiConsoleOutDeviceGuid
647     );
648 
649   ConPlatformUnInstallProtocol (
650     This,
651     ControllerHandle,
652     &gEfiStandardErrorDeviceGuid
653     );
654 
655   //
656   // Close the Simple Text Output Protocol
657   //
658   gBS->CloseProtocol (
659         ControllerHandle,
660         &gEfiSimpleTextOutProtocolGuid,
661         This->DriverBindingHandle,
662         ControllerHandle
663         );
664 
665   return EFI_SUCCESS;
666 }
667 
668 
669 /**
670   Uninstall the specified protocol.
671 
672   @param This            Protocol instance pointer.
673   @param Handle          Handle of device to uninstall protocol on.
674   @param ProtocolGuid    The specified protocol need to be uninstalled.
675 
676 **/
677 VOID
ConPlatformUnInstallProtocol(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Handle,IN EFI_GUID * ProtocolGuid)678 ConPlatformUnInstallProtocol (
679   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
680   IN  EFI_HANDLE                   Handle,
681   IN  EFI_GUID                     *ProtocolGuid
682   )
683 {
684   EFI_STATUS  Status;
685 
686   Status = gBS->OpenProtocol (
687                   Handle,
688                   ProtocolGuid,
689                   NULL,
690                   This->DriverBindingHandle,
691                   Handle,
692                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
693                   );
694 
695   if (!EFI_ERROR (Status)) {
696     gBS->UninstallMultipleProtocolInterfaces (
697            Handle,
698            ProtocolGuid,
699            NULL,
700            NULL
701            );
702   }
703 
704   return ;
705 }
706 
707 /**
708   Get the necessary size of buffer and read the variable.
709 
710   First get the necessary size of buffer. Then read the
711   EFI variable (Name) and return a dynamically allocated
712   buffer. On failure return NULL.
713 
714   @param  Name             String part of EFI variable name
715 
716   @return Dynamically allocated memory that contains a copy of the EFI variable.
717           Caller is repsoncible freeing the buffer. Return NULL means Variable
718           was not read.
719 
720 **/
721 VOID *
ConPlatformGetVariable(IN CHAR16 * Name)722 ConPlatformGetVariable (
723   IN  CHAR16    *Name
724   )
725 {
726   EFI_STATUS  Status;
727   VOID        *Buffer;
728   UINTN       BufferSize;
729 
730   BufferSize  = 0;
731   Buffer      = NULL;
732 
733   //
734   // Test to see if the variable exists.  If it doesn't, return NULL.
735   //
736   Status = gRT->GetVariable (
737                   Name,
738                   &gEfiGlobalVariableGuid,
739                   NULL,
740                   &BufferSize,
741                   Buffer
742                   );
743 
744   if (Status == EFI_BUFFER_TOO_SMALL) {
745     //
746     // Allocate the buffer to return
747     //
748     Buffer = AllocatePool (BufferSize);
749     if (Buffer == NULL) {
750       return NULL;
751     }
752     //
753     // Read variable into the allocated buffer.
754     //
755     Status = gRT->GetVariable (
756                     Name,
757                     &gEfiGlobalVariableGuid,
758                     NULL,
759                     &BufferSize,
760                     Buffer
761                     );
762     if (EFI_ERROR (Status)) {
763       FreePool (Buffer);
764       //
765       // To make sure Buffer is NULL if any error occurs.
766       //
767       Buffer = NULL;
768     }
769   }
770 
771   return Buffer;
772 }
773 
774 /**
775   Function returns TRUE when the two input device paths point to the two
776   GOP child handles that have the same parent.
777 
778   @param Left    A pointer to a device path data structure.
779   @param Right   A pointer to a device path data structure.
780 
781   @retval TRUE  Left and Right share the same parent.
782   @retval FALSE Left and Right don't share the same parent or either of them is not
783                 a GOP device path.
784 **/
785 BOOLEAN
IsGopSibling(IN EFI_DEVICE_PATH_PROTOCOL * Left,IN EFI_DEVICE_PATH_PROTOCOL * Right)786 IsGopSibling (
787   IN EFI_DEVICE_PATH_PROTOCOL  *Left,
788   IN EFI_DEVICE_PATH_PROTOCOL  *Right
789   )
790 {
791   EFI_DEVICE_PATH_PROTOCOL  *NodeLeft;
792   EFI_DEVICE_PATH_PROTOCOL  *NodeRight;
793 
794   for (NodeLeft = Left; !IsDevicePathEndType (NodeLeft); NodeLeft = NextDevicePathNode (NodeLeft)) {
795     if ((DevicePathType (NodeLeft) == ACPI_DEVICE_PATH && DevicePathSubType (NodeLeft) == ACPI_ADR_DP) ||
796         (DevicePathType (NodeLeft) == HARDWARE_DEVICE_PATH && DevicePathSubType (NodeLeft) == HW_CONTROLLER_DP &&
797          DevicePathType (NextDevicePathNode (NodeLeft)) == ACPI_DEVICE_PATH && DevicePathSubType (NextDevicePathNode (NodeLeft)) == ACPI_ADR_DP)) {
798       break;
799     }
800   }
801 
802   if (IsDevicePathEndType (NodeLeft)) {
803     return FALSE;
804   }
805 
806   for (NodeRight = Right; !IsDevicePathEndType (NodeRight); NodeRight = NextDevicePathNode (NodeRight)) {
807     if ((DevicePathType (NodeRight) == ACPI_DEVICE_PATH && DevicePathSubType (NodeRight) == ACPI_ADR_DP) ||
808         (DevicePathType (NodeRight) == HARDWARE_DEVICE_PATH && DevicePathSubType (NodeRight) == HW_CONTROLLER_DP &&
809          DevicePathType (NextDevicePathNode (NodeRight)) == ACPI_DEVICE_PATH && DevicePathSubType (NextDevicePathNode (NodeRight)) == ACPI_ADR_DP)) {
810       break;
811     }
812   }
813 
814   if (IsDevicePathEndType (NodeRight)) {
815     return FALSE;
816   }
817 
818   if (((UINTN) NodeLeft - (UINTN) Left) != ((UINTN) NodeRight - (UINTN) Right)) {
819     return FALSE;
820   }
821 
822   return (BOOLEAN) (CompareMem (Left, Right, (UINTN) NodeLeft - (UINTN) Left) == 0);
823 }
824 
825 /**
826   Function compares a device path data structure to that of all the nodes of a
827   second device path instance.
828 
829   @param Multi           A pointer to a multi-instance device path data structure.
830   @param Single          A pointer to a single-instance device path data structure.
831   @param NewDevicePath   If Delete is TRUE, this parameter must not be null, and it
832                          points to the remaining device path data structure.
833                          (remaining device path = Multi - Single.)
834   @param Delete          If TRUE, means removing Single from Multi.
835                          If FALSE, the routine just check whether Single matches
836                          with any instance in Multi.
837 
838   @retval EFI_SUCCESS           If the Single is contained within Multi.
839   @retval EFI_NOT_FOUND         If the Single is not contained within Multi.
840   @retval EFI_INVALID_PARAMETER Multi is NULL.
841   @retval EFI_INVALID_PARAMETER Single is NULL.
842   @retval EFI_INVALID_PARAMETER NewDevicePath is NULL when Delete is TRUE.
843 
844 **/
845 EFI_STATUS
ConPlatformMatchDevicePaths(IN EFI_DEVICE_PATH_PROTOCOL * Multi,IN EFI_DEVICE_PATH_PROTOCOL * Single,OUT EFI_DEVICE_PATH_PROTOCOL ** NewDevicePath OPTIONAL,IN BOOLEAN Delete)846 ConPlatformMatchDevicePaths (
847   IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,
848   IN  EFI_DEVICE_PATH_PROTOCOL  *Single,
849   OUT EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath OPTIONAL,
850   IN  BOOLEAN                   Delete
851   )
852 {
853   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
854   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath1;
855   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath2;
856   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
857   UINTN                     Size;
858 
859   //
860   // The passed in DevicePath should not be NULL
861   //
862   if ((Multi == NULL) || (Single == NULL)) {
863     return EFI_INVALID_PARAMETER;
864   }
865 
866   //
867   // If performing Delete operation, the NewDevicePath must not be NULL.
868   //
869   if (Delete) {
870     if (NewDevicePath == NULL) {
871       return EFI_INVALID_PARAMETER;
872     }
873   }
874 
875   TempDevicePath1 = NULL;
876 
877   DevicePath      = Multi;
878   DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);
879 
880   //
881   // Search for the match of 'Single' in 'Multi'
882   //
883   while (DevicePathInst != NULL) {
884     if ((CompareMem (Single, DevicePathInst, Size) == 0) || IsGopSibling (Single, DevicePathInst)) {
885       if (!Delete) {
886         //
887         // If Delete is FALSE, return EFI_SUCCESS if Single is found in Multi.
888         //
889         FreePool (DevicePathInst);
890         return EFI_SUCCESS;
891       }
892     } else {
893       if (Delete) {
894         //
895         // If the node of Multi does not match Single, then added it back to the result.
896         // That is, the node matching Single will be dropped and deleted from result.
897         //
898         TempDevicePath2 = AppendDevicePathInstance (
899                             TempDevicePath1,
900                             DevicePathInst
901                             );
902         if (TempDevicePath1 != NULL) {
903           FreePool (TempDevicePath1);
904         }
905         TempDevicePath1 = TempDevicePath2;
906       }
907     }
908 
909     FreePool (DevicePathInst);
910     DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
911   }
912 
913   if (Delete) {
914     //
915     // Return the new device path data structure with specified node deleted.
916     //
917     *NewDevicePath = TempDevicePath1;
918     return EFI_SUCCESS;
919   }
920 
921   return EFI_NOT_FOUND;
922 }
923 
924 /**
925   Update console environment variables.
926 
927   @param  VariableName    Console environment variables, ConOutDev, ConInDev
928                           ErrOutDev, ConIn ,ConOut or ErrOut.
929   @param  DevicePath      Console devcie's device path.
930   @param  Operation       Variable operations, including APPEND, CHECK and DELETE.
931 
932   @retval EFI_SUCCESS           Variable operates successfully.
933   @retval EFI_OUT_OF_RESOURCES  If variable cannot be appended.
934   @retval other                 Variable updating failed.
935 
936 **/
937 EFI_STATUS
ConPlatformUpdateDeviceVariable(IN CHAR16 * VariableName,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN CONPLATFORM_VAR_OPERATION Operation)938 ConPlatformUpdateDeviceVariable (
939   IN  CHAR16                    *VariableName,
940   IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
941   IN  CONPLATFORM_VAR_OPERATION Operation
942   )
943 {
944   EFI_STATUS                Status;
945   EFI_DEVICE_PATH_PROTOCOL  *VariableDevicePath;
946   EFI_DEVICE_PATH_PROTOCOL  *NewVariableDevicePath;
947 
948   VariableDevicePath    = NULL;
949   NewVariableDevicePath = NULL;
950 
951   //
952   // Get Variable according to variable name.
953   // The memory for Variable is allocated within ConPlatformGetVarible(),
954   // it is the caller's responsibility to free the memory before return.
955   //
956   VariableDevicePath = ConPlatformGetVariable (VariableName);
957 
958   if (Operation != Delete) {
959     //
960     // Match specified DevicePath in Console Variable.
961     //
962     Status = ConPlatformMatchDevicePaths (
963                VariableDevicePath,
964                DevicePath,
965                NULL,
966                FALSE
967                );
968 
969     if ((Operation == Check) || (!EFI_ERROR (Status))) {
970       //
971       // Branch here includes 2 cases:
972       // 1. Operation is CHECK, simply return Status.
973       // 2. Operation is APPEND, and device path already exists in variable, also return.
974       //
975       if (VariableDevicePath != NULL) {
976         FreePool (VariableDevicePath);
977       }
978 
979       return Status;
980     }
981     //
982     // We reach here to append a device path that does not exist in variable.
983     //
984     Status = EFI_SUCCESS;
985     NewVariableDevicePath = AppendDevicePathInstance (
986                               VariableDevicePath,
987                               DevicePath
988                               );
989     if (NewVariableDevicePath == NULL) {
990       Status = EFI_OUT_OF_RESOURCES;
991     }
992 
993   } else {
994     //
995     // We reach here to remove DevicePath from the environment variable that
996     // is a multi-instance device path.
997     //
998     Status = ConPlatformMatchDevicePaths (
999                VariableDevicePath,
1000                DevicePath,
1001                &NewVariableDevicePath,
1002                TRUE
1003                );
1004   }
1005 
1006   if (VariableDevicePath != NULL) {
1007     FreePool (VariableDevicePath);
1008   }
1009 
1010   if (EFI_ERROR (Status)) {
1011     return Status;
1012   }
1013 
1014   if (NewVariableDevicePath != NULL) {
1015     //
1016     // Update Console Environment Variable.
1017     //
1018     Status = gRT->SetVariable (
1019                     VariableName,
1020                     &gEfiGlobalVariableGuid,
1021                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1022                     GetDevicePathSize (NewVariableDevicePath),
1023                     NewVariableDevicePath
1024                     );
1025 
1026     FreePool (NewVariableDevicePath);
1027   }
1028 
1029   return Status;
1030 }
1031 
1032 /**
1033   Check if the device supports hot-plug through its device path.
1034 
1035   This function could be updated to check more types of Hot Plug devices.
1036   Currently, it checks USB and PCCard device.
1037 
1038   @param  DevicePath            Pointer to device's device path.
1039 
1040   @retval TRUE                  The devcie is a hot-plug device
1041   @retval FALSE                 The devcie is not a hot-plug device.
1042 
1043 **/
1044 BOOLEAN
IsHotPlugDevice(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)1045 IsHotPlugDevice (
1046   IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath
1047   )
1048 {
1049   EFI_DEVICE_PATH_PROTOCOL     *CheckDevicePath;
1050 
1051   CheckDevicePath = DevicePath;
1052   while (!IsDevicePathEnd (CheckDevicePath)) {
1053     //
1054     // Check device whether is hot plug device or not throught Device Path
1055     //
1056     if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) &&
1057         (DevicePathSubType (CheckDevicePath) == MSG_USB_DP ||
1058          DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP ||
1059          DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) {
1060       //
1061       // If Device is USB device
1062       //
1063       return TRUE;
1064     }
1065     if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) &&
1066         (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) {
1067       //
1068       // If Device is PCCard
1069       //
1070       return TRUE;
1071     }
1072 
1073     CheckDevicePath = NextDevicePathNode (CheckDevicePath);
1074   }
1075 
1076   return FALSE;
1077 }
1078 
1079 /**
1080   Update ConOutDev and ErrOutDev variables to add the device path of
1081   GOP controller itself and the sibling controllers.
1082 
1083   @param  DevicePath            Pointer to device's device path.
1084 
1085   @retval TRUE                  The devcie is a GOP device.
1086   @retval FALSE                 The devcie is not a GOP device.
1087 
1088 **/
1089 BOOLEAN
ConPlatformUpdateGopCandidate(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)1090 ConPlatformUpdateGopCandidate (
1091   IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath
1092   )
1093 {
1094   EFI_STATUS                           Status;
1095   EFI_HANDLE                           PciHandle;
1096   EFI_HANDLE                           GopHandle;
1097   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
1098   UINTN                                EntryCount;
1099   UINTN                                Index;
1100   EFI_DEVICE_PATH_PROTOCOL             *ChildDevicePath;
1101   EFI_DEVICE_PATH_PROTOCOL             *TempDevicePath;
1102 
1103   //
1104   // Check whether it's a GOP device.
1105   //
1106   TempDevicePath = DevicePath;
1107   Status = gBS->LocateDevicePath (&gEfiGraphicsOutputProtocolGuid, &TempDevicePath, &GopHandle);
1108   if (EFI_ERROR (Status)) {
1109     return FALSE;
1110   }
1111   //
1112   // Get the parent PciIo handle in order to find all the children
1113   //
1114   Status = gBS->LocateDevicePath (&gEfiPciIoProtocolGuid, &DevicePath, &PciHandle);
1115   if (EFI_ERROR (Status)) {
1116     return FALSE;
1117   }
1118 
1119   Status = gBS->OpenProtocolInformation (
1120                   PciHandle,
1121                   &gEfiPciIoProtocolGuid,
1122                   &OpenInfoBuffer,
1123                   &EntryCount
1124                   );
1125   if (EFI_ERROR (Status)) {
1126     return FALSE;
1127   }
1128 
1129   for (Index = 0; Index < EntryCount; Index++) {
1130     //
1131     // Query all the children created by the GOP driver
1132     //
1133     if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
1134       Status = gBS->OpenProtocol (
1135                       OpenInfoBuffer[Index].ControllerHandle,
1136                       &gEfiDevicePathProtocolGuid,
1137                       (VOID **) &ChildDevicePath,
1138                       NULL,
1139                       NULL,
1140                       EFI_OPEN_PROTOCOL_GET_PROTOCOL
1141                       );
1142       if (!EFI_ERROR (Status)) {
1143         //
1144         // Append the device path to ConOutDev and ErrOutDev
1145         //
1146         ConPlatformUpdateDeviceVariable (L"ConOutDev", ChildDevicePath, Append);
1147         ConPlatformUpdateDeviceVariable (L"ErrOutDev", ChildDevicePath, Append);
1148       }
1149     }
1150   }
1151   FreePool (OpenInfoBuffer);
1152 
1153   return TRUE;
1154 }
1155