56bdd11693926ffdc7360f1a929173b196acaf4d
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Console / ConPlatformDxe / ConPlatform.c
1 /** @file\r
2   Console Platfrom DXE Driver, install Console Device Guids and update Console\r
3   Environment Variables.\r
4 \r
5 Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
6 All rights reserved. This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution.  The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10 \r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 \r
14 **/\r
15 \r
16 #include <ConPlatform.h>\r
17 \r
18 \r
19 EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextInDriverBinding = {\r
20   ConPlatformTextInDriverBindingSupported,\r
21   ConPlatformTextInDriverBindingStart,\r
22   ConPlatformTextInDriverBindingStop,\r
23   0xa,\r
24   NULL,\r
25   NULL\r
26 };\r
27 \r
28 EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextOutDriverBinding = {\r
29   ConPlatformTextOutDriverBindingSupported,\r
30   ConPlatformTextOutDriverBindingStart,\r
31   ConPlatformTextOutDriverBindingStop,\r
32   0xa,\r
33   NULL,\r
34   NULL\r
35 };\r
36 \r
37 /**\r
38   The user Entry Point for module ConPlatform. The user code starts with this function.\r
39 \r
40   @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
41   @param[in] SystemTable    A pointer to the EFI System Table.\r
42 \r
43   @retval EFI_SUCCESS       The entry point is executed successfully.\r
44   @retval other             Some error occurs when executing this entry point.\r
45 \r
46 **/\r
47 EFI_STATUS\r
48 EFIAPI\r
49 InitializeConPlatform(\r
50   IN EFI_HANDLE           ImageHandle,\r
51   IN EFI_SYSTEM_TABLE     *SystemTable\r
52   )\r
53 {\r
54   EFI_STATUS              Status;\r
55 \r
56   //\r
57   // Install driver model protocol(s).\r
58   //\r
59   Status = EfiLibInstallDriverBindingComponentName2 (\r
60              ImageHandle,\r
61              SystemTable,\r
62              &gConPlatformTextInDriverBinding,\r
63              ImageHandle,\r
64              &gConPlatformComponentName,\r
65              &gConPlatformComponentName2\r
66              );\r
67   ASSERT_EFI_ERROR (Status);\r
68 \r
69   Status = EfiLibInstallDriverBindingComponentName2 (\r
70              ImageHandle,\r
71              SystemTable,\r
72              &gConPlatformTextOutDriverBinding,\r
73              NULL,\r
74              &gConPlatformComponentName,\r
75              &gConPlatformComponentName2\r
76              );\r
77   ASSERT_EFI_ERROR (Status);\r
78 \r
79 \r
80   return Status;\r
81 }\r
82 \r
83 \r
84 /**\r
85   Test to see if EFI Text In Protocol could be supported on the ControllerHandle. \r
86 \r
87   @param  This                Protocol instance pointer.\r
88   @param  ControllerHandle    Handle of device to test.\r
89   @param  RemainingDevicePath Optional parameter use to pick a specific child\r
90                               device to start.\r
91 \r
92   @retval EFI_SUCCESS         This driver supports this device\r
93   @retval other               This driver does not support this device\r
94 \r
95 **/\r
96 EFI_STATUS\r
97 EFIAPI\r
98 ConPlatformTextInDriverBindingSupported (\r
99   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
100   IN  EFI_HANDLE                   ControllerHandle,\r
101   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
102   )\r
103 {\r
104   return ConPlatformDriverBindingSupported (\r
105           This,\r
106           ControllerHandle,\r
107           RemainingDevicePath,\r
108           &gEfiSimpleTextInProtocolGuid\r
109           );\r
110 }\r
111 \r
112 \r
113 /**\r
114   Test to see if EFI Text Out Protocol could be supported on the ControllerHandle. \r
115 \r
116   @param  This                Protocol instance pointer.\r
117   @param  ControllerHandle    Handle of device to test.\r
118   @param  RemainingDevicePath Optional parameter use to pick a specific child\r
119                               device to start.\r
120 \r
121   @retval EFI_SUCCESS         This driver supports this device\r
122   @retval other               This driver does not support this device\r
123 \r
124 **/\r
125 EFI_STATUS\r
126 EFIAPI\r
127 ConPlatformTextOutDriverBindingSupported (\r
128   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
129   IN  EFI_HANDLE                   ControllerHandle,\r
130   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
131   )\r
132 {\r
133   return ConPlatformDriverBindingSupported (\r
134           This,\r
135           ControllerHandle,\r
136           RemainingDevicePath,\r
137           &gEfiSimpleTextOutProtocolGuid\r
138           );\r
139 }\r
140 \r
141 \r
142 /**\r
143   Test to see if specific Protocol could be supported on the ControllerHandle. \r
144 \r
145   @param  This                Protocol instance pointer.\r
146   @param  ControllerHandle    Handle of device to test.\r
147   @param  RemainingDevicePath Optional parameter use to pick a specific child\r
148                               device to start.\r
149   @param  ProtocolGuid        The specfic protocol.\r
150 \r
151   @retval EFI_SUCCESS         This driver supports this device\r
152   @retval other               This driver does not support this device\r
153 \r
154 **/\r
155 EFI_STATUS\r
156 ConPlatformDriverBindingSupported (\r
157   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
158   IN  EFI_HANDLE                   ControllerHandle,\r
159   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath,\r
160   IN  EFI_GUID                     *ProtocolGuid\r
161   )\r
162 {\r
163   EFI_STATUS  Status;\r
164   VOID        *Interface;\r
165 \r
166   //\r
167   // Test to see if this is a physical device by checking to see if\r
168   // it has a Device Path Protocol\r
169   //\r
170   Status = gBS->OpenProtocol (\r
171                   ControllerHandle,\r
172                   &gEfiDevicePathProtocolGuid,\r
173                   NULL,\r
174                   This->DriverBindingHandle,\r
175                   ControllerHandle,\r
176                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
177                   );\r
178   if (EFI_ERROR (Status)) {\r
179     return Status;\r
180   }\r
181   //\r
182   // Test to see if this device supports the specific Protocol\r
183   //\r
184   Status = gBS->OpenProtocol (\r
185                   ControllerHandle,\r
186                   ProtocolGuid,\r
187                   (VOID **) &Interface,\r
188                   This->DriverBindingHandle,\r
189                   ControllerHandle,\r
190                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
191                   );\r
192   if (EFI_ERROR (Status)) {\r
193     return Status;\r
194   }\r
195 \r
196   gBS->CloseProtocol (\r
197         ControllerHandle,\r
198         ProtocolGuid,\r
199         This->DriverBindingHandle,\r
200         ControllerHandle\r
201         );\r
202 \r
203   return EFI_SUCCESS;\r
204 }\r
205 \r
206 /**\r
207   Start this driver on ControllerHandle by opening Simple Text In protocol,\r
208   reading Device Path, and installing Console In Devcice GUID on ControllerHandle.\r
209 \r
210   If this devcie is not one hot-plug devce, append its device path into the \r
211   console environment variables ConInDev.\r
212   \r
213   @param  This                 Protocol instance pointer.\r
214   @param  ControllerHandle     Handle of device to bind driver to\r
215   @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
216                                device to start.\r
217 \r
218   @retval EFI_SUCCESS          This driver is added to ControllerHandle\r
219   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle\r
220   @retval other                This driver does not support this device.\r
221 \r
222 **/\r
223 EFI_STATUS\r
224 EFIAPI\r
225 ConPlatformTextInDriverBindingStart (\r
226   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,\r
227   IN  EFI_HANDLE                    ControllerHandle,\r
228   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
229   )\r
230 {\r
231   EFI_STATUS                  Status;\r
232   EFI_DEVICE_PATH_PROTOCOL    *DevicePath;\r
233   EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn;\r
234 \r
235   //\r
236   // Get the Device Path Protocol so the environment variables can be updated\r
237   //\r
238   Status = gBS->OpenProtocol (\r
239                   ControllerHandle,\r
240                   &gEfiDevicePathProtocolGuid,\r
241                   (VOID **) &DevicePath,\r
242                   This->DriverBindingHandle,\r
243                   ControllerHandle,\r
244                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
245                   );\r
246   if (EFI_ERROR (Status)) {\r
247     return Status;\r
248   }\r
249   //\r
250   // Open the Simple Input Protocol BY_DRIVER\r
251   //\r
252   Status = gBS->OpenProtocol (\r
253                   ControllerHandle,\r
254                   &gEfiSimpleTextInProtocolGuid,\r
255                   (VOID **) &TextIn,\r
256                   This->DriverBindingHandle,\r
257                   ControllerHandle,\r
258                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
259                   );\r
260   if (EFI_ERROR (Status)) {\r
261     return Status;\r
262   }\r
263   //\r
264   // Check the device handle, if it is a hot plug device,\r
265   // do not put the device path into ConInDev, and install\r
266   // gEfiConsoleInDeviceGuid to the device handle directly.\r
267   // The policy is, make hot plug device plug in and play immediately.\r
268   //\r
269   if (IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) {\r
270     gBS->InstallMultipleProtocolInterfaces (\r
271           &ControllerHandle,\r
272           &gEfiConsoleInDeviceGuid,\r
273           NULL,\r
274           NULL\r
275           );\r
276   } else {\r
277     //\r
278     // Append the device path to the ConInDev environment variable\r
279     //\r
280     ConPlatformUpdateDeviceVariable (\r
281       L"ConInDev",\r
282       DevicePath,\r
283       APPEND\r
284       );\r
285 \r
286     //\r
287     // If the device path is an instance in the ConIn environment variable,\r
288     // then install EfiConsoleInDeviceGuid onto ControllerHandle\r
289     //\r
290     Status = ConPlatformUpdateDeviceVariable (\r
291               L"ConIn",\r
292               DevicePath,\r
293               CHECK\r
294               );\r
295 \r
296     if (!EFI_ERROR (Status)) {\r
297       gBS->InstallMultipleProtocolInterfaces (\r
298             &ControllerHandle,\r
299             &gEfiConsoleInDeviceGuid,\r
300             NULL,\r
301             NULL\r
302             );\r
303     } else {\r
304       gBS->CloseProtocol (\r
305             ControllerHandle,\r
306             &gEfiSimpleTextInProtocolGuid,\r
307             This->DriverBindingHandle,\r
308             ControllerHandle\r
309             );\r
310     }\r
311   }\r
312 \r
313   return EFI_SUCCESS;\r
314 }\r
315 \r
316 /**\r
317   Start this driver on ControllerHandle by opening Simple Text Out protocol,\r
318   reading Device Path, and installing Console Out Devcic GUID, Standard Error\r
319   Device GUID on ControllerHandle.\r
320 \r
321   If this devcie is not one hot-plug devce, append its device path into the \r
322   console environment variables ConOutDev, StdErrDev.\r
323   \r
324   @param  This                 Protocol instance pointer.\r
325   @param  ControllerHandle     Handle of device to bind driver to\r
326   @param  RemainingDevicePath  Optional parameter use to pick a specific child\r
327                                device to start.\r
328 \r
329   @retval EFI_SUCCESS          This driver is added to ControllerHandle\r
330   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle\r
331   @retval other                This driver does not support this device\r
332 \r
333 **/\r
334 EFI_STATUS\r
335 EFIAPI\r
336 ConPlatformTextOutDriverBindingStart (\r
337   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,\r
338   IN  EFI_HANDLE                    ControllerHandle,\r
339   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
340   )\r
341 {\r
342   EFI_STATUS                    Status;\r
343   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;\r
344   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *TextOut;\r
345   BOOLEAN                       NeedClose;\r
346 \r
347   NeedClose = TRUE;\r
348 \r
349   //\r
350   // Get the Device Path Protocol so the environment variables can be updated\r
351   //\r
352   Status = gBS->OpenProtocol (\r
353                   ControllerHandle,\r
354                   &gEfiDevicePathProtocolGuid,\r
355                   (VOID **) &DevicePath,\r
356                   This->DriverBindingHandle,\r
357                   ControllerHandle,\r
358                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
359                   );\r
360   if (EFI_ERROR (Status)) {\r
361     return Status;\r
362   }\r
363   //\r
364   // Open the Simple Text Output Protocol BY_DRIVER\r
365   //\r
366   Status = gBS->OpenProtocol (\r
367                   ControllerHandle,\r
368                   &gEfiSimpleTextOutProtocolGuid,\r
369                   (VOID **) &TextOut,\r
370                   This->DriverBindingHandle,\r
371                   ControllerHandle,\r
372                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
373                   );\r
374   if (EFI_ERROR (Status)) {\r
375     return Status;\r
376   }\r
377   //\r
378   // Check the device handle, if it is a hot plug device,\r
379   // do not put the device path into ConOutDev and StdErrDev,\r
380   // and install gEfiConsoleOutDeviceGuid to the device handle directly.\r
381   // The policy is, make hot plug device plug in and play immediately.\r
382   //\r
383   if (IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) {\r
384     gBS->InstallMultipleProtocolInterfaces (\r
385           &ControllerHandle,\r
386           &gEfiConsoleOutDeviceGuid,\r
387           NULL,\r
388           NULL\r
389           );\r
390   } else {\r
391     //\r
392     // Append the device path to the ConOutDev environment variable\r
393     //\r
394     ConPlatformUpdateDeviceVariable (\r
395       L"ConOutDev",\r
396       DevicePath,\r
397       APPEND\r
398       );\r
399     //\r
400     // Append the device path to the StdErrDev environment variable\r
401     //\r
402     ConPlatformUpdateDeviceVariable (\r
403       L"ErrOutDev",\r
404       DevicePath,\r
405       APPEND\r
406       );\r
407 \r
408     //\r
409     // If the device path is an instance in the ConOut environment variable,\r
410     // then install EfiConsoleOutDeviceGuid onto ControllerHandle\r
411     //\r
412     Status = ConPlatformUpdateDeviceVariable (\r
413               L"ConOut",\r
414               DevicePath,\r
415               CHECK\r
416               );\r
417 \r
418     if (!EFI_ERROR (Status)) {\r
419       NeedClose = FALSE;\r
420       Status = gBS->InstallMultipleProtocolInterfaces (\r
421                       &ControllerHandle,\r
422                       &gEfiConsoleOutDeviceGuid,\r
423                       NULL,\r
424                       NULL\r
425                       );\r
426     }\r
427     //\r
428     // If the device path is an instance in the StdErr environment variable,\r
429     // then install EfiStandardErrorDeviceGuid onto ControllerHandle\r
430     //\r
431     Status = ConPlatformUpdateDeviceVariable (\r
432               L"ErrOut",\r
433               DevicePath,\r
434               CHECK\r
435               );\r
436     if (!EFI_ERROR (Status)) {\r
437       NeedClose = FALSE;\r
438       gBS->InstallMultipleProtocolInterfaces (\r
439             &ControllerHandle,\r
440             &gEfiStandardErrorDeviceGuid,\r
441             NULL,\r
442             NULL\r
443             );\r
444     }\r
445 \r
446     if (NeedClose) {\r
447       gBS->CloseProtocol (\r
448             ControllerHandle,\r
449             &gEfiSimpleTextOutProtocolGuid,\r
450             This->DriverBindingHandle,\r
451             ControllerHandle\r
452             );\r
453     }\r
454   }\r
455 \r
456   return EFI_SUCCESS;\r
457 }\r
458 \r
459 /**\r
460   Stop this driver on ControllerHandle by removing Console In Devcice GUID \r
461   and closing the Simple Text In protocol on ControllerHandle.\r
462 \r
463   @param  This              Protocol instance pointer.\r
464   @param  ControllerHandle  Handle of device to stop driver on\r
465   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
466                             children is zero stop the entire bus driver.\r
467   @param  ChildHandleBuffer List of Child Handles to Stop.\r
468 \r
469   @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
470   @retval other             This driver was not removed from this device\r
471 \r
472 **/\r
473 EFI_STATUS\r
474 EFIAPI\r
475 ConPlatformTextInDriverBindingStop (\r
476   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
477   IN  EFI_HANDLE                   ControllerHandle,\r
478   IN  UINTN                        NumberOfChildren,\r
479   IN  EFI_HANDLE                   *ChildHandleBuffer\r
480   )\r
481 {\r
482   EFI_STATUS                Status;\r
483   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
484 \r
485   //\r
486   // hot plug device is not included into the console associated variables,\r
487   // so no need to check variable for those hot plug devices.\r
488   //\r
489   if (!IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) {\r
490     //\r
491     // Get the Device Path Protocol so the environment variables can be updated\r
492     //\r
493     Status = gBS->OpenProtocol (\r
494                     ControllerHandle,\r
495                     &gEfiDevicePathProtocolGuid,\r
496                     (VOID **) &DevicePath,\r
497                     This->DriverBindingHandle,\r
498                     ControllerHandle,\r
499                     EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
500                     );\r
501     if (!EFI_ERROR (Status)) {\r
502       //\r
503       // Remove DevicePath from ConInDev\r
504       //\r
505       ConPlatformUpdateDeviceVariable (\r
506         L"ConInDev",\r
507         DevicePath,\r
508         DELETE\r
509         );\r
510     }\r
511   }\r
512   //\r
513   // Uninstall the Console Device GUIDs from Controller Handle\r
514   //\r
515   ConPlatformUnInstallProtocol (\r
516     This,\r
517     ControllerHandle,\r
518     &gEfiConsoleInDeviceGuid\r
519     );\r
520 \r
521   //\r
522   // Close the Simple Input Protocol\r
523   //\r
524   gBS->CloseProtocol (\r
525         ControllerHandle,\r
526         &gEfiSimpleTextInProtocolGuid,\r
527         This->DriverBindingHandle,\r
528         ControllerHandle\r
529         );\r
530 \r
531   return EFI_SUCCESS;\r
532 }\r
533 \r
534 \r
535 /**\r
536   Stop this driver on ControllerHandle by removing Console Out Devcice GUID \r
537   and closing the Simple Text Out protocol on ControllerHandle.\r
538 \r
539   @param  This              Protocol instance pointer.\r
540   @param  ControllerHandle  Handle of device to stop driver on\r
541   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of\r
542                             children is zero stop the entire bus driver.\r
543   @param  ChildHandleBuffer List of Child Handles to Stop.\r
544 \r
545   @retval EFI_SUCCESS       This driver is removed ControllerHandle\r
546   @retval other             This driver was not removed from this device\r
547 \r
548 **/\r
549 EFI_STATUS\r
550 EFIAPI\r
551 ConPlatformTextOutDriverBindingStop (\r
552   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
553   IN  EFI_HANDLE                   ControllerHandle,\r
554   IN  UINTN                        NumberOfChildren,\r
555   IN  EFI_HANDLE                   *ChildHandleBuffer\r
556   )\r
557 {\r
558   EFI_STATUS                Status;\r
559   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
560 \r
561   //\r
562   // hot plug device is not included into the console associated variables,\r
563   // so no need to check variable for those hot plug devices.\r
564   //\r
565   if (!IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) {\r
566     //\r
567     // Get the Device Path Protocol so the environment variables can be updated\r
568     //\r
569     Status = gBS->OpenProtocol (\r
570                     ControllerHandle,\r
571                     &gEfiDevicePathProtocolGuid,\r
572                     (VOID **) &DevicePath,\r
573                     This->DriverBindingHandle,\r
574                     ControllerHandle,\r
575                     EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
576                     );\r
577     if (!EFI_ERROR (Status)) {\r
578       //\r
579       // Remove DevicePath from ConOutDev, and StdErrDev\r
580       //\r
581       ConPlatformUpdateDeviceVariable (\r
582         L"ConOutDev",\r
583         DevicePath,\r
584         DELETE\r
585         );\r
586       ConPlatformUpdateDeviceVariable (\r
587         L"ErrOutDev",\r
588         DevicePath,\r
589         DELETE\r
590         );\r
591     }\r
592   }\r
593   //\r
594   // Uninstall the Console Device GUIDs from Controller Handle\r
595   //\r
596   ConPlatformUnInstallProtocol (\r
597     This,\r
598     ControllerHandle,\r
599     &gEfiConsoleOutDeviceGuid\r
600     );\r
601 \r
602   ConPlatformUnInstallProtocol (\r
603     This,\r
604     ControllerHandle,\r
605     &gEfiStandardErrorDeviceGuid\r
606     );\r
607 \r
608   //\r
609   // Close the Simple Text Output Protocol\r
610   //\r
611   gBS->CloseProtocol (\r
612         ControllerHandle,\r
613         &gEfiSimpleTextOutProtocolGuid,\r
614         This->DriverBindingHandle,\r
615         ControllerHandle\r
616         );\r
617 \r
618   return EFI_SUCCESS;\r
619 }\r
620 \r
621 \r
622 /**\r
623   Unstall the specific protocol.\r
624 \r
625   @param This            Protocol instance pointer.\r
626   @param Handle          Handle of device to unstall protocol on.\r
627   @param ProtocolGuid    The specific protocol need to be uninstalled.\r
628 \r
629   @return None.\r
630 \r
631 **/\r
632 VOID\r
633 ConPlatformUnInstallProtocol (\r
634   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
635   IN  EFI_HANDLE                   Handle,\r
636   IN  EFI_GUID                     *ProtocolGuid\r
637   )\r
638 {\r
639   EFI_STATUS  Status;\r
640 \r
641   Status = gBS->OpenProtocol (\r
642                   Handle,\r
643                   ProtocolGuid,\r
644                   NULL,\r
645                   This->DriverBindingHandle,\r
646                   Handle,\r
647                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
648                   );\r
649 \r
650   if (!EFI_ERROR (Status)) {\r
651     gBS->UninstallMultipleProtocolInterfaces (\r
652           Handle,\r
653           ProtocolGuid,\r
654           NULL,\r
655           NULL\r
656           );\r
657   }\r
658 \r
659   return ;\r
660 }\r
661 \r
662 /**\r
663   Read the EFI variable (Name) and return a dynamically allocated\r
664   buffer, and the size of the buffer. On failure return NULL.\r
665 \r
666 \r
667   @param  Name             String part of EFI variable name\r
668 \r
669   @return Dynamically allocated memory that contains a copy of the EFI variable.\r
670           Caller is repsoncible freeing the buffer.\r
671           NULL - Variable was not read\r
672 \r
673 **/\r
674 VOID *\r
675 ConPlatformGetVariable (\r
676   IN  CHAR16    *Name\r
677   )\r
678 {\r
679   EFI_STATUS  Status;\r
680   VOID        *Buffer;\r
681   UINTN       BufferSize;\r
682 \r
683   BufferSize  = 0;\r
684   Buffer      = NULL;\r
685 \r
686   //\r
687   // Test to see if the variable exists.  If it doesn't reuturn NULL\r
688   //\r
689   Status = gRT->GetVariable (\r
690                   Name,\r
691                   &gEfiGlobalVariableGuid,\r
692                   NULL,\r
693                   &BufferSize,\r
694                   Buffer\r
695                   );\r
696 \r
697   if (Status == EFI_BUFFER_TOO_SMALL) {\r
698     //\r
699     // Allocate the buffer to return\r
700     //\r
701     Buffer = AllocatePool (BufferSize);\r
702     if (Buffer == NULL) {\r
703       return NULL;\r
704     }\r
705     //\r
706     // Read variable into the allocated buffer.\r
707     //\r
708     Status = gRT->GetVariable (\r
709                     Name,\r
710                     &gEfiGlobalVariableGuid,\r
711                     NULL,\r
712                     &BufferSize,\r
713                     Buffer\r
714                     );\r
715     if (EFI_ERROR (Status)) {\r
716       FreePool (Buffer);\r
717       Buffer = NULL;\r
718     }\r
719   }\r
720 \r
721   return Buffer;\r
722 }\r
723 \r
724 /**\r
725   Function compares a device path data structure to that of all the nodes of a\r
726   second device path instance.\r
727 \r
728 \r
729   @param Multi           A pointer to a multi-instance device path data structure.\r
730   @param Single          A pointer to a single-instance device path data structure.\r
731   @param NewDevicePath   If Delete is TRUE, this parameter must not be null, and it\r
732                          points to the remaining device path data structure.\r
733                          (remaining device path = Multi - Single.)\r
734   @param Delete          If TRUE, means removing Single from Multi.\r
735                          If FALSE, the routine just check whether Single matches\r
736                          with any instance in Multi.\r
737 \r
738   @return The function returns EFI_SUCCESS if the Single is contained within Multi.\r
739           Otherwise, EFI_NOT_FOUND is returned.\r
740 \r
741 **/\r
742 EFI_STATUS\r
743 ConPlatformMatchDevicePaths (\r
744   IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
745   IN  EFI_DEVICE_PATH_PROTOCOL  *Single,\r
746   IN  EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath OPTIONAL,\r
747   IN  BOOLEAN                   Delete\r
748   )\r
749 {\r
750   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
751   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
752   EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;\r
753   UINTN                     Size;\r
754 \r
755   //\r
756   // The passed in DevicePath should not be NULL\r
757   //\r
758   if ((Multi == NULL) || (Single == NULL)) {\r
759     return EFI_NOT_FOUND;\r
760   }\r
761   //\r
762   // if performing Delete operation, the NewDevicePath must not be NULL.\r
763   //\r
764   TempDevicePath  = NULL;\r
765 \r
766   DevicePath      = Multi;\r
767   DevicePathInst  = GetNextDevicePathInstance (&DevicePath, &Size);\r
768 \r
769   //\r
770   // search for the match of 'Single' in 'Multi'\r
771   //\r
772   while (DevicePathInst != NULL) {\r
773     if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
774       if (!Delete) {\r
775         FreePool (DevicePathInst);\r
776         return EFI_SUCCESS;\r
777       }\r
778     } else {\r
779       if (Delete) {\r
780         TempDevicePath = AppendDevicePathInstance (\r
781                             NULL,\r
782                             DevicePathInst\r
783                             );\r
784       }\r
785     }\r
786 \r
787     FreePool (DevicePathInst);\r
788     DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
789   }\r
790 \r
791   if (Delete) {\r
792     *NewDevicePath = TempDevicePath;\r
793     return EFI_SUCCESS;\r
794   }\r
795 \r
796   return EFI_NOT_FOUND;\r
797 }\r
798 \r
799 /**\r
800   Update console devicein console environment variables. \r
801 \r
802   @param  VariableName    Console environment variables, ConOutDev, ConInDev\r
803                           StdErrDev, ConIn or ConOut.\r
804   @param  DevicePath      Console devcie's device path.\r
805   @param  Operation       Variable operations, such as APPEND or DELETE.\r
806 \r
807   @retval EFI_SUCCESS           Variable operates successfully.\r
808   @retval EFI_OUT_OF_RESOURCES  If variable cannot be appended.\r
809   @retval other                 Variable updating failed.\r
810 \r
811 **/\r
812 EFI_STATUS\r
813 ConPlatformUpdateDeviceVariable (\r
814   IN  CHAR16                    *VariableName,\r
815   IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
816   IN  CONPLATFORM_VAR_OPERATION Operation\r
817   )\r
818 {\r
819   EFI_STATUS                Status;\r
820   EFI_DEVICE_PATH_PROTOCOL  *VariableDevicePath;\r
821   EFI_DEVICE_PATH_PROTOCOL  *NewVariableDevicePath;\r
822 \r
823   VariableDevicePath    = NULL;\r
824   NewVariableDevicePath = NULL;\r
825 \r
826   //\r
827   // Get Variable according to variable name.\r
828   // The memory for Variable is allocated within ConPlatformGetVarible(),\r
829   // it is the caller's responsibility to free the memory before return.\r
830   //\r
831   VariableDevicePath = ConPlatformGetVariable (VariableName);\r
832 \r
833   if (Operation != DELETE) {\r
834 \r
835     Status = ConPlatformMatchDevicePaths (\r
836               VariableDevicePath,\r
837               DevicePath,\r
838               NULL,\r
839               FALSE\r
840               );\r
841 \r
842     if ((Operation == CHECK) || (!EFI_ERROR (Status))) {\r
843       //\r
844       // The device path is already in the variable\r
845       //\r
846       if (VariableDevicePath != NULL) {\r
847         FreePool (VariableDevicePath);\r
848       }\r
849 \r
850       return Status;\r
851     }\r
852     //\r
853     // The device path is not in variable. Append DevicePath to the\r
854     // environment variable that is a multi-instance device path.\r
855     //\r
856     Status = EFI_SUCCESS;\r
857     NewVariableDevicePath = AppendDevicePathInstance (\r
858                               VariableDevicePath,\r
859                               DevicePath\r
860                               );\r
861     if (NewVariableDevicePath == NULL) {\r
862       Status = EFI_OUT_OF_RESOURCES;\r
863     }\r
864 \r
865   } else {\r
866     //\r
867     // Remove DevicePath from the environment variable that\r
868     // is a multi-instance device path.\r
869     //\r
870     Status = ConPlatformMatchDevicePaths (\r
871               VariableDevicePath,\r
872               DevicePath,\r
873               &NewVariableDevicePath,\r
874               TRUE\r
875               );\r
876   }\r
877 \r
878   if (VariableDevicePath != NULL) {\r
879     FreePool (VariableDevicePath);\r
880   }\r
881 \r
882   if (EFI_ERROR (Status)) {\r
883     return Status;\r
884   }\r
885 \r
886   if (NewVariableDevicePath != NULL) {\r
887     Status = gRT->SetVariable (\r
888                     VariableName,\r
889                     &gEfiGlobalVariableGuid,\r
890                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
891                     GetDevicePathSize (NewVariableDevicePath),\r
892                     NewVariableDevicePath\r
893                     );\r
894 \r
895     FreePool (NewVariableDevicePath);\r
896   }\r
897 \r
898   return Status;\r
899 }\r
900 \r
901 /**\r
902   Check if the device is one hot-plug supported.\r
903 \r
904   @param  DriverBindingHandle   Protocol instance pointer.\r
905   @param  ControllerHandle      Handle of device to check.\r
906 \r
907   @retval TRUE                  The devcie is a hot-plug device\r
908   @retval FALSE                 The devcie is not a hot-plug device.\r
909 \r
910 **/\r
911 BOOLEAN\r
912 IsHotPlugDevice (\r
913   EFI_HANDLE    DriverBindingHandle,\r
914   EFI_HANDLE    ControllerHandle\r
915   )\r
916 {\r
917   EFI_STATUS  Status;\r
918 \r
919   //\r
920   // HotPlugDeviceGuid indicates ControllerHandle stands for a hot plug device.\r
921   //\r
922   Status = gBS->OpenProtocol (\r
923                   ControllerHandle,\r
924                   &gEfiHotPlugDeviceGuid,\r
925                   NULL,\r
926                   DriverBindingHandle,\r
927                   ControllerHandle,\r
928                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
929                   );\r
930   if (EFI_ERROR (Status)) {\r
931     return FALSE;\r
932   }\r
933 \r
934   return TRUE;\r
935 }\r