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