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