MdePkg:
[mirror_edk2.git] / EdkModulePkg / Universal / ConPlatform / Dxe / ConPlatform.c
1 /*++
2
3 Copyright (c) 2006 - 2007, 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 ConPlatformTextInDriverBindingStop,
26 0xa,
27 NULL,
28 NULL
29 };
30
31 EFI_DRIVER_BINDING_PROTOCOL gConPlatformTextOutDriverBinding = {
32 ConPlatformTextOutDriverBindingSupported,
33 ConPlatformTextOutDriverBindingStart,
34 ConPlatformTextOutDriverBindingStop,
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 BOOLEAN NeedClose;
291
292 NeedClose = TRUE;
293
294 //
295 // Get the Device Path Protocol so the environment variables can be updated
296 //
297 Status = gBS->OpenProtocol (
298 ControllerHandle,
299 &gEfiDevicePathProtocolGuid,
300 (VOID **) &DevicePath,
301 This->DriverBindingHandle,
302 ControllerHandle,
303 EFI_OPEN_PROTOCOL_GET_PROTOCOL
304 );
305 if (EFI_ERROR (Status)) {
306 return Status;
307 }
308 //
309 // Open the Simple Text Output Protocol BY_DRIVER
310 //
311 Status = gBS->OpenProtocol (
312 ControllerHandle,
313 &gEfiSimpleTextOutProtocolGuid,
314 (VOID **) &TextOut,
315 This->DriverBindingHandle,
316 ControllerHandle,
317 EFI_OPEN_PROTOCOL_BY_DRIVER
318 );
319 if (EFI_ERROR (Status)) {
320 return Status;
321 }
322 //
323 // Check the device handle, if it is a hot plug device,
324 // do not put the device path into ConOutDev and StdErrDev,
325 // and install gEfiConsoleOutDeviceGuid to the device handle directly.
326 // The policy is, make hot plug device plug in and play immediately.
327 //
328 if (IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) {
329 gBS->InstallMultipleProtocolInterfaces (
330 &ControllerHandle,
331 &gEfiConsoleOutDeviceGuid,
332 NULL,
333 NULL
334 );
335 } else {
336 //
337 // Append the device path to the ConOutDev environment variable
338 //
339 ConPlatformUpdateDeviceVariable (
340 VarConsoleOutDev,
341 DevicePath,
342 APPEND
343 );
344 //
345 // Append the device path to the StdErrDev environment variable
346 //
347 ConPlatformUpdateDeviceVariable (
348 VarErrorOutDev,
349 DevicePath,
350 APPEND
351 );
352
353 //
354 // If the device path is an instance in the ConOut environment variable,
355 // then install EfiConsoleOutDeviceGuid onto ControllerHandle
356 //
357 Status = ConPlatformUpdateDeviceVariable (
358 VarConsoleOut,
359 DevicePath,
360 CHECK
361 );
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 ConPlatformTextInDriverBindingStop (
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
447 //
448 ConPlatformUpdateDeviceVariable (
449 VarConsoleInpDev,
450 DevicePath,
451 DELETE
452 );
453 }
454 }
455 //
456 // Uninstall the Console Device GUIDs from Controller Handle
457 //
458 ConPlatformUnInstallProtocol (
459 This,
460 ControllerHandle,
461 &gEfiConsoleInDeviceGuid
462 );
463
464 //
465 // Close the Simple Input Protocol
466 //
467 gBS->CloseProtocol (
468 ControllerHandle,
469 &gEfiSimpleTextInProtocolGuid,
470 This->DriverBindingHandle,
471 ControllerHandle
472 );
473
474 return EFI_SUCCESS;
475 }
476
477 EFI_STATUS
478 EFIAPI
479 ConPlatformTextOutDriverBindingStop (
480 IN EFI_DRIVER_BINDING_PROTOCOL *This,
481 IN EFI_HANDLE ControllerHandle,
482 IN UINTN NumberOfChildren,
483 IN EFI_HANDLE *ChildHandleBuffer
484 )
485 /*++
486
487 Routine Description:
488
489 Arguments:
490 (Standard DriverBinding Protocol Stop() function)
491
492 Returns:
493
494 None
495
496 --*/
497 {
498 EFI_STATUS Status;
499 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
500
501 //
502 // hot plug device is not included into the console associated variables,
503 // so no need to check variable for those hot plug devices.
504 //
505 if (!IsHotPlugDevice (This->DriverBindingHandle, ControllerHandle)) {
506 //
507 // Get the Device Path Protocol so the environment variables can be updated
508 //
509 Status = gBS->OpenProtocol (
510 ControllerHandle,
511 &gEfiDevicePathProtocolGuid,
512 (VOID **) &DevicePath,
513 This->DriverBindingHandle,
514 ControllerHandle,
515 EFI_OPEN_PROTOCOL_GET_PROTOCOL
516 );
517 if (!EFI_ERROR (Status)) {
518 //
519 // Remove DevicePath from ConOutDev, and StdErrDev
520 //
521 ConPlatformUpdateDeviceVariable (
522 VarConsoleOutDev,
523 DevicePath,
524 DELETE
525 );
526 ConPlatformUpdateDeviceVariable (
527 VarErrorOutDev,
528 DevicePath,
529 DELETE
530 );
531 }
532 }
533 //
534 // Uninstall the Console Device GUIDs from Controller Handle
535 //
536 ConPlatformUnInstallProtocol (
537 This,
538 ControllerHandle,
539 &gEfiConsoleOutDeviceGuid
540 );
541
542 ConPlatformUnInstallProtocol (
543 This,
544 ControllerHandle,
545 &gEfiStandardErrorDeviceGuid
546 );
547
548 //
549 // Close the Simple Text Output Protocol
550 //
551 gBS->CloseProtocol (
552 ControllerHandle,
553 &gEfiSimpleTextOutProtocolGuid,
554 This->DriverBindingHandle,
555 ControllerHandle
556 );
557
558 return EFI_SUCCESS;
559 }
560
561
562 VOID
563 ConPlatformUnInstallProtocol (
564 IN EFI_DRIVER_BINDING_PROTOCOL *This,
565 IN EFI_HANDLE Handle,
566 IN EFI_GUID *ProtocolGuid
567 )
568 {
569 EFI_STATUS Status;
570
571 Status = gBS->OpenProtocol (
572 Handle,
573 ProtocolGuid,
574 NULL,
575 This->DriverBindingHandle,
576 Handle,
577 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
578 );
579
580 if (!EFI_ERROR (Status)) {
581 gBS->UninstallMultipleProtocolInterfaces (
582 Handle,
583 ProtocolGuid,
584 NULL,
585 NULL
586 );
587 }
588
589 return ;
590 }
591
592 VOID *
593 ConPlatformGetVariable (
594 IN CHAR16 *Name
595 )
596 /*++
597
598 Routine Description:
599 Read the EFI variable (Name) and return a dynamically allocated
600 buffer, and the size of the buffer. On failure return NULL.
601
602 Arguments:
603 Name - String part of EFI variable name
604
605 Returns:
606 Dynamically allocated memory that contains a copy of the EFI variable.
607 Caller is repsoncible freeing the buffer.
608
609 NULL - Variable was not read
610
611 --*/
612 {
613 EFI_STATUS Status;
614 VOID *Buffer;
615 UINTN BufferSize;
616
617 BufferSize = 0;
618 Buffer = NULL;
619
620 //
621 // Test to see if the variable exists. If it doesn't reuturn NULL
622 //
623 Status = gRT->GetVariable (
624 Name,
625 &gEfiGlobalVariableGuid,
626 NULL,
627 &BufferSize,
628 Buffer
629 );
630
631 if (Status == EFI_BUFFER_TOO_SMALL) {
632 //
633 // Allocate the buffer to return
634 //
635 Buffer = AllocatePool (BufferSize);
636 if (Buffer == NULL) {
637 return NULL;
638 }
639 //
640 // Read variable into the allocated buffer.
641 //
642 Status = gRT->GetVariable (
643 Name,
644 &gEfiGlobalVariableGuid,
645 NULL,
646 &BufferSize,
647 Buffer
648 );
649 if (EFI_ERROR (Status)) {
650 FreePool (Buffer);
651 Buffer = NULL;
652 }
653 }
654
655 return Buffer;
656 }
657
658 EFI_STATUS
659 ConPlatformMatchDevicePaths (
660 IN EFI_DEVICE_PATH_PROTOCOL * Multi,
661 IN EFI_DEVICE_PATH_PROTOCOL * Single,
662 IN EFI_DEVICE_PATH_PROTOCOL **NewDevicePath OPTIONAL,
663 IN BOOLEAN Delete
664 )
665 /*++
666
667 Routine Description:
668 Function compares a device path data structure to that of all the nodes of a
669 second device path instance.
670
671 Arguments:
672 Multi - A pointer to a multi-instance device path data structure.
673
674 Single - A pointer to a single-instance device path data structure.
675
676 NewDevicePath - If Delete is TRUE, this parameter must not be null, and it
677 points to the remaining device path data structure.
678 (remaining device path = Multi - Single.)
679
680 Delete - If TRUE, means removing Single from Multi.
681 If FALSE, the routine just check whether Single matches
682 with any instance in Multi.
683
684 Returns:
685
686 The function returns EFI_SUCCESS if the Single is contained within Multi.
687 Otherwise, EFI_NOT_FOUND is returned.
688
689 --*/
690 {
691 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
692 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath1;
693 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath2;
694 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
695 UINTN Size;
696
697 //
698 // The passed in DevicePath should not be NULL
699 //
700 if ((!Multi) || (!Single)) {
701 return EFI_NOT_FOUND;
702 }
703 //
704 // if performing Delete operation, the NewDevicePath must not be NULL.
705 //
706 TempDevicePath1 = NULL;
707
708 DevicePath = Multi;
709 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
710
711 //
712 // search for the match of 'Single' in 'Multi'
713 //
714 while (DevicePathInst) {
715 if (CompareMem (Single, DevicePathInst, Size) == 0) {
716 if (!Delete) {
717 FreePool (DevicePathInst);
718 return EFI_SUCCESS;
719 }
720 } else {
721 if (Delete) {
722 TempDevicePath2 = AppendDevicePathInstance (
723 TempDevicePath1,
724 DevicePathInst
725 );
726 if (TempDevicePath1 != NULL) {
727 FreePool (TempDevicePath1);
728 }
729 TempDevicePath1 = TempDevicePath2;
730 }
731 }
732
733 FreePool (DevicePathInst);
734 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
735 }
736
737 if (Delete) {
738 *NewDevicePath = TempDevicePath1;
739 return EFI_SUCCESS;
740 }
741
742 return EFI_NOT_FOUND;
743 }
744
745 EFI_STATUS
746 ConPlatformUpdateDeviceVariable (
747 IN CHAR16 *VariableName,
748 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
749 IN CONPLATFORM_VAR_OPERATION Operation
750 )
751 /*++
752
753 Routine Description:
754
755
756 Arguments:
757
758 Returns:
759
760 None
761
762 --*/
763 {
764 EFI_STATUS Status;
765 EFI_DEVICE_PATH_PROTOCOL *VariableDevicePath;
766 EFI_DEVICE_PATH_PROTOCOL *NewVariableDevicePath;
767
768 VariableDevicePath = NULL;
769 NewVariableDevicePath = NULL;
770
771 //
772 // Get Variable according to variable name.
773 // The memory for Variable is allocated within ConPlatformGetVarible(),
774 // it is the caller's responsibility to free the memory before return.
775 //
776 VariableDevicePath = ConPlatformGetVariable (VariableName);
777
778 if (Operation != DELETE) {
779
780 Status = ConPlatformMatchDevicePaths (
781 VariableDevicePath,
782 DevicePath,
783 NULL,
784 FALSE
785 );
786
787 if ((Operation == CHECK) || (!EFI_ERROR (Status))) {
788 //
789 // The device path is already in the variable
790 //
791 if (VariableDevicePath != NULL) {
792 FreePool (VariableDevicePath);
793 }
794
795 return Status;
796 }
797 //
798 // The device path is not in variable. Append DevicePath to the
799 // environment variable that is a multi-instance device path.
800 //
801 Status = EFI_SUCCESS;
802 NewVariableDevicePath = AppendDevicePathInstance (
803 VariableDevicePath,
804 DevicePath
805 );
806 if (NewVariableDevicePath == NULL) {
807 Status = EFI_OUT_OF_RESOURCES;
808 }
809
810 } else {
811 //
812 // Remove DevicePath from the environment variable that
813 // is a multi-instance device path.
814 //
815 Status = ConPlatformMatchDevicePaths (
816 VariableDevicePath,
817 DevicePath,
818 &NewVariableDevicePath,
819 TRUE
820 );
821 }
822
823 if (VariableDevicePath != NULL) {
824 FreePool (VariableDevicePath);
825 }
826
827 if (EFI_ERROR (Status)) {
828 return Status;
829 }
830
831 Status = gRT->SetVariable (
832 VariableName,
833 &gEfiGlobalVariableGuid,
834 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
835 GetDevicePathSize (NewVariableDevicePath),
836 NewVariableDevicePath
837 );
838
839 FreePool (NewVariableDevicePath);
840
841 return Status;
842 }
843
844 BOOLEAN
845 IsHotPlugDevice (
846 EFI_HANDLE DriverBindingHandle,
847 EFI_HANDLE ControllerHandle
848 )
849 {
850 EFI_STATUS Status;
851
852 //
853 // HotPlugDeviceGuid indicates ControllerHandle stands for a hot plug device.
854 //
855 Status = gBS->OpenProtocol (
856 ControllerHandle,
857 &gEfiHotPlugDeviceGuid,
858 NULL,
859 DriverBindingHandle,
860 ControllerHandle,
861 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
862 );
863 if (EFI_ERROR (Status)) {
864 return FALSE;
865 }
866
867 return TRUE;
868 }