]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/UefiLib/UefiLib.c
retried GetGraphicsBitMapFromFV()and GetGraphicsBitMapFromFVEx(), instead using GetSe...
[mirror_edk2.git] / MdePkg / Library / UefiLib / UefiLib.c
CommitLineData
e386b444 1/** @file\r
5ad97f35 2 The UEFI Library provides functions and macros that simplify the development of \r
3 UEFI Drivers and UEFI Applications. These functions and macros help manage EFI \r
4 events, build simple locks utilizing EFI Task Priority Levels (TPLs), install \r
5 EFI Driver Model related protocols, manage Unicode string tables for UEFI Drivers, \r
6 and print messages on the console output and standard error devices.\r
e386b444 7\r
8 Copyright (c) 2006 - 2007, Intel Corporation<BR>\r
9 All rights reserved. This program and the accompanying materials\r
10 are licensed and made available under the terms and conditions of the BSD License\r
11 which accompanies this distribution. The full text of the license may be found at\r
12 http://opensource.org/licenses/bsd-license.php\r
13\r
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
e386b444 17**/\r
18\r
1efcc4ae 19\r
f734a10a 20#include "UefiLibInternal.h"\r
e386b444 21\r
22/**\r
23 Compare whether two names of languages are identical.\r
24\r
25 @param Language1 Name of language 1.\r
26 @param Language2 Name of language 2.\r
27\r
28 @retval TRUE Language 1 and language 2 are the same.\r
29 @retval FALSE Language 1 and language 2 are not the same.\r
30\r
31**/\r
e386b444 32BOOLEAN\r
33CompareIso639LanguageCode (\r
34 IN CONST CHAR8 *Language1,\r
35 IN CONST CHAR8 *Language2\r
36 )\r
37{\r
38 UINT32 Name1;\r
39 UINT32 Name2;\r
40\r
41 Name1 = ReadUnaligned24 ((CONST UINT32 *) Language1);\r
42 Name2 = ReadUnaligned24 ((CONST UINT32 *) Language2);\r
43\r
44 return (BOOLEAN) (Name1 == Name2);\r
45}\r
46\r
47/**\r
48 This function searches the list of configuration tables stored in the EFI System\r
49 Table for a table with a GUID that matches TableGuid. If a match is found,\r
50 then a pointer to the configuration table is returned in Table, and EFI_SUCCESS\r
51 is returned. If a matching GUID is not found, then EFI_NOT_FOUND is returned.\r
9edc73ad 52 If TableGuid is NULL, then ASSERT().\r
53 If Table is NULL, then ASSERT().\r
e386b444 54\r
55 @param TableGuid Pointer to table's GUID type..\r
56 @param Table Pointer to the table associated with TableGuid in the EFI System Table.\r
57\r
58 @retval EFI_SUCCESS A configuration table matching TableGuid was found.\r
59 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.\r
60\r
61**/\r
62EFI_STATUS\r
63EFIAPI\r
64EfiGetSystemConfigurationTable (\r
65 IN EFI_GUID *TableGuid,\r
66 OUT VOID **Table\r
67 )\r
68{\r
69 EFI_SYSTEM_TABLE *SystemTable;\r
70 UINTN Index;\r
71\r
72 ASSERT (TableGuid != NULL);\r
73 ASSERT (Table != NULL);\r
74\r
75 SystemTable = gST;\r
76 *Table = NULL;\r
77 for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {\r
78 if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) {\r
79 *Table = SystemTable->ConfigurationTable[Index].VendorTable;\r
80 return EFI_SUCCESS;\r
81 }\r
82 }\r
83\r
84 return EFI_NOT_FOUND;\r
85}\r
86\r
87/**\r
88 This function causes the notification function to be executed for every protocol\r
89 of type ProtocolGuid instance that exists in the system when this function is\r
90 invoked. In addition, every time a protocol of type ProtocolGuid instance is\r
91 installed or reinstalled, the notification function is also executed.\r
92\r
93 @param ProtocolGuid Supplies GUID of the protocol upon whose installation the event is fired.\r
94 @param NotifyTpl Supplies the task priority level of the event notifications.\r
95 @param NotifyFunction Supplies the function to notify when the event is signaled.\r
96 @param NotifyContext The context parameter to pass to NotifyFunction.\r
97 @param Registration A pointer to a memory location to receive the registration value.\r
98\r
99 @return The notification event that was created.\r
100\r
101**/\r
102EFI_EVENT\r
103EFIAPI\r
104EfiCreateProtocolNotifyEvent(\r
105 IN EFI_GUID *ProtocolGuid,\r
106 IN EFI_TPL NotifyTpl,\r
107 IN EFI_EVENT_NOTIFY NotifyFunction,\r
108 IN VOID *NotifyContext, OPTIONAL\r
109 OUT VOID **Registration\r
110 )\r
111{\r
112 EFI_STATUS Status;\r
113 EFI_EVENT Event;\r
114\r
115 //\r
116 // Create the event\r
117 //\r
118\r
119 Status = gBS->CreateEvent (\r
120 EVT_NOTIFY_SIGNAL,\r
121 NotifyTpl,\r
122 NotifyFunction,\r
123 NotifyContext,\r
124 &Event\r
125 );\r
126 ASSERT_EFI_ERROR (Status);\r
127\r
128 //\r
129 // Register for protocol notifactions on this event\r
130 //\r
131\r
132 Status = gBS->RegisterProtocolNotify (\r
133 ProtocolGuid,\r
134 Event,\r
135 Registration\r
136 );\r
137\r
138 ASSERT_EFI_ERROR (Status);\r
139\r
140 //\r
141 // Kick the event so we will perform an initial pass of\r
142 // current installed drivers\r
143 //\r
144\r
145 gBS->SignalEvent (Event);\r
146 return Event;\r
147}\r
148\r
149/**\r
150 This function creates an event using NotifyTpl, NoifyFunction, and NotifyContext.\r
151 This event is signaled with EfiNamedEventSignal(). This provide the ability for\r
152 one or more listeners on the same event named by the GUID specified by Name.\r
9edc73ad 153 If Name is NULL, then ASSERT().\r
154 If NotifyTpl is not a legal TPL value, then ASSERT().\r
155 If NotifyFunction is NULL, then ASSERT().\r
e386b444 156\r
157 @param Name Supplies GUID name of the event.\r
158 @param NotifyTpl Supplies the task priority level of the event notifications.\r
159 @param NotifyFunction Supplies the function to notify when the event is signaled.\r
160 @param NotifyContext The context parameter to pass to NotifyFunction.\r
161 @param Registration A pointer to a memory location to receive the registration value.\r
162\r
163 @retval EFI_SUCCESS A named event was created.\r
164 @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.\r
165\r
166**/\r
167EFI_STATUS\r
168EFIAPI\r
169EfiNamedEventListen (\r
170 IN CONST EFI_GUID *Name,\r
171 IN EFI_TPL NotifyTpl,\r
172 IN EFI_EVENT_NOTIFY NotifyFunction,\r
173 IN CONST VOID *NotifyContext, OPTIONAL\r
174 OUT VOID *Registration OPTIONAL\r
175 )\r
176{\r
177 EFI_STATUS Status;\r
178 EFI_EVENT Event;\r
179 VOID *RegistrationLocal;\r
180\r
9edc73ad 181 ASSERT (Name != NULL);\r
182 ASSERT (NotifyFunction != NULL);\r
183 ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);\r
184 \r
e386b444 185 //\r
186 // Create event\r
187 //\r
188 Status = gBS->CreateEvent (\r
189 EVT_NOTIFY_SIGNAL,\r
190 NotifyTpl,\r
191 NotifyFunction,\r
192 (VOID *) NotifyContext,\r
193 &Event\r
194 );\r
195 ASSERT_EFI_ERROR (Status);\r
196\r
197 //\r
198 // The Registration is not optional to RegisterProtocolNotify().\r
199 // To make it optional to EfiNamedEventListen(), may need to substitute with a local.\r
200 //\r
201 if (Registration != NULL) {\r
202 RegistrationLocal = Registration;\r
203 } else {\r
204 RegistrationLocal = &RegistrationLocal;\r
205 }\r
206\r
207 //\r
208 // Register for an installation of protocol interface\r
209 //\r
210\r
211 Status = gBS->RegisterProtocolNotify (\r
212 (EFI_GUID *) Name,\r
213 Event,\r
214 RegistrationLocal\r
215 );\r
216 ASSERT_EFI_ERROR (Status);\r
217\r
9edc73ad 218 return Status;\r
e386b444 219}\r
220\r
221/**\r
222 This function signals the named event specified by Name. The named event must\r
223 have been created with EfiNamedEventListen().\r
224\r
225 @param Name Supplies GUID name of the event.\r
226\r
227 @retval EFI_SUCCESS A named event was signaled.\r
228 @retval EFI_OUT_OF_RESOURCES There are not enough resource to signal the named event.\r
229\r
230**/\r
231EFI_STATUS\r
232EFIAPI\r
233EfiNamedEventSignal (\r
234 IN CONST EFI_GUID *Name\r
235 )\r
236{\r
237 EFI_STATUS Status;\r
238 EFI_HANDLE Handle;\r
239\r
240 Handle = NULL;\r
241 Status = gBS->InstallProtocolInterface (\r
242 &Handle,\r
243 (EFI_GUID *) Name,\r
244 EFI_NATIVE_INTERFACE,\r
245 NULL\r
246 );\r
247 ASSERT_EFI_ERROR (Status);\r
248\r
249 Status = gBS->UninstallProtocolInterface (\r
250 Handle,\r
251 (EFI_GUID *) Name,\r
252 NULL\r
253 );\r
254 ASSERT_EFI_ERROR (Status);\r
255\r
9edc73ad 256 return Status;\r
e386b444 257}\r
258\r
259/**\r
260 Returns the current TPL.\r
261\r
262 This function returns the current TPL. There is no EFI service to directly\r
263 retrieve the current TPL. Instead, the RaiseTPL() function is used to raise\r
264 the TPL to TPL_HIGH_LEVEL. This will return the current TPL. The TPL level\r
265 can then immediately be restored back to the current TPL level with a call\r
266 to RestoreTPL().\r
267\r
268 @param VOID\r
269\r
42eedea9 270 @retval EFI_TPL The current TPL.\r
e386b444 271\r
272**/\r
273EFI_TPL\r
274EFIAPI\r
275EfiGetCurrentTpl (\r
276 VOID\r
277 )\r
278{\r
279 EFI_TPL Tpl;\r
280\r
281 Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
282 gBS->RestoreTPL (Tpl);\r
283\r
284 return Tpl;\r
285}\r
286\r
287\r
288/**\r
289 This function initializes a basic mutual exclusion lock to the released state\r
290 and returns the lock. Each lock provides mutual exclusion access at its task\r
291 priority level. Since there is no preemption or multiprocessor support in EFI,\r
292 acquiring the lock only consists of raising to the locks TPL.\r
9edc73ad 293 If Lock is NULL, then ASSERT().\r
294 If Priority is not a valid TPL value, then ASSERT().\r
e386b444 295\r
296 @param Lock A pointer to the lock data structure to initialize.\r
297 @param Priority EFI TPL associated with the lock.\r
298\r
299 @return The lock.\r
300\r
301**/\r
302EFI_LOCK *\r
303EFIAPI\r
304EfiInitializeLock (\r
305 IN OUT EFI_LOCK *Lock,\r
306 IN EFI_TPL Priority\r
307 )\r
308{\r
309 ASSERT (Lock != NULL);\r
310 ASSERT (Priority <= TPL_HIGH_LEVEL);\r
311\r
312 Lock->Tpl = Priority;\r
313 Lock->OwnerTpl = TPL_APPLICATION;\r
314 Lock->Lock = EfiLockReleased ;\r
315 return Lock;\r
316}\r
317\r
318/**\r
319 This function raises the system's current task priority level to the task\r
320 priority level of the mutual exclusion lock. Then, it places the lock in the\r
321 acquired state.\r
9edc73ad 322 If Lock is NULL, then ASSERT().\r
323 If Lock is not initialized, then ASSERT().\r
324 If Lock is already in the acquired state, then ASSERT().\r
e386b444 325\r
42eedea9 326 @param Lock The task lock with priority level.\r
e386b444 327\r
328**/\r
329VOID\r
330EFIAPI\r
331EfiAcquireLock (\r
332 IN EFI_LOCK *Lock\r
333 )\r
334{\r
335 ASSERT (Lock != NULL);\r
336 ASSERT (Lock->Lock == EfiLockReleased);\r
337\r
338 Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);\r
339 Lock->Lock = EfiLockAcquired;\r
340}\r
341\r
342/**\r
343 This function raises the system's current task priority level to the task\r
344 priority level of the mutual exclusion lock. Then, it attempts to place the\r
345 lock in the acquired state.\r
346\r
347 @param Lock A pointer to the lock to acquire.\r
348\r
349 @retval EFI_SUCCESS The lock was acquired.\r
350 @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.\r
351\r
352**/\r
353EFI_STATUS\r
354EFIAPI\r
355EfiAcquireLockOrFail (\r
356 IN EFI_LOCK *Lock\r
357 )\r
358{\r
359\r
360 ASSERT (Lock != NULL);\r
361 ASSERT (Lock->Lock != EfiLockUninitialized);\r
362\r
363 if (Lock->Lock == EfiLockAcquired) {\r
364 //\r
365 // Lock is already owned, so bail out\r
366 //\r
367 return EFI_ACCESS_DENIED;\r
368 }\r
369\r
370 Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);\r
371\r
372 Lock->Lock = EfiLockAcquired;\r
373\r
374 return EFI_SUCCESS;\r
375}\r
376\r
377/**\r
378 This function transitions a mutual exclusion lock from the acquired state to\r
379 the released state, and restores the system's task priority level to its\r
380 previous level.\r
381\r
382 @param Lock A pointer to the lock to release.\r
383\r
384**/\r
385VOID\r
386EFIAPI\r
387EfiReleaseLock (\r
388 IN EFI_LOCK *Lock\r
389 )\r
390{\r
391 EFI_TPL Tpl;\r
392\r
393 ASSERT (Lock != NULL);\r
394 ASSERT (Lock->Lock == EfiLockAcquired);\r
395\r
396 Tpl = Lock->OwnerTpl;\r
397\r
398 Lock->Lock = EfiLockReleased;\r
399\r
400 gBS->RestoreTPL (Tpl);\r
401}\r
402\r
403/**\r
404 Tests whether a controller handle is being managed by a specific driver.\r
405\r
406 This function tests whether the driver specified by DriverBindingHandle is\r
407 currently managing the controller specified by ControllerHandle. This test\r
408 is performed by evaluating if the the protocol specified by ProtocolGuid is\r
409 present on ControllerHandle and is was opened by DriverBindingHandle with an\r
410 attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.\r
411 If ProtocolGuid is NULL, then ASSERT().\r
412\r
413 @param ControllerHandle A handle for a controller to test.\r
414 @param DriverBindingHandle Specifies the driver binding handle for the\r
415 driver.\r
416 @param ProtocolGuid Specifies the protocol that the driver specified\r
417 by DriverBindingHandle opens in its Start()\r
418 function.\r
419\r
420 @retval EFI_SUCCESS ControllerHandle is managed by the driver\r
421 specifed by DriverBindingHandle.\r
422 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver\r
423 specifed by DriverBindingHandle.\r
424\r
425**/\r
426EFI_STATUS\r
427EFIAPI\r
428EfiTestManagedDevice (\r
429 IN CONST EFI_HANDLE ControllerHandle,\r
430 IN CONST EFI_HANDLE DriverBindingHandle,\r
431 IN CONST EFI_GUID *ProtocolGuid\r
432 )\r
433{\r
434 EFI_STATUS Status;\r
435 VOID *ManagedInterface;\r
436\r
437 ASSERT (ProtocolGuid != NULL);\r
438\r
439 Status = gBS->OpenProtocol (\r
440 ControllerHandle,\r
441 (EFI_GUID *) ProtocolGuid,\r
442 &ManagedInterface,\r
443 DriverBindingHandle,\r
444 ControllerHandle,\r
445 EFI_OPEN_PROTOCOL_BY_DRIVER\r
446 );\r
447 if (!EFI_ERROR (Status)) {\r
448 gBS->CloseProtocol (\r
449 ControllerHandle,\r
450 (EFI_GUID *) ProtocolGuid,\r
451 DriverBindingHandle,\r
452 ControllerHandle\r
453 );\r
454 return EFI_UNSUPPORTED;\r
455 }\r
456\r
457 if (Status != EFI_ALREADY_STARTED) {\r
458 return EFI_UNSUPPORTED;\r
459 }\r
460\r
461 return EFI_SUCCESS;\r
462}\r
463\r
464/**\r
465 Tests whether a child handle is a child device of the controller.\r
466\r
467 This function tests whether ChildHandle is one of the children of\r
468 ControllerHandle. This test is performed by checking to see if the protocol\r
469 specified by ProtocolGuid is present on ControllerHandle and opened by\r
470 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
471 If ProtocolGuid is NULL, then ASSERT().\r
472\r
473 @param ControllerHandle A handle for a (parent) controller to test.\r
474 @param ChildHandle A child handle to test.\r
42eedea9 475 @param ProtocolGuid Supplies the protocol that the child controller\r
e386b444 476 opens on its parent controller.\r
477\r
478 @retval EFI_SUCCESS ChildHandle is a child of the ControllerHandle.\r
479 @retval EFI_UNSUPPORTED ChildHandle is not a child of the\r
480 ControllerHandle.\r
481\r
482**/\r
483EFI_STATUS\r
484EFIAPI\r
485EfiTestChildHandle (\r
486 IN CONST EFI_HANDLE ControllerHandle,\r
487 IN CONST EFI_HANDLE ChildHandle,\r
488 IN CONST EFI_GUID *ProtocolGuid\r
489 )\r
490{\r
491 EFI_STATUS Status;\r
492 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;\r
493 UINTN EntryCount;\r
494 UINTN Index;\r
495\r
496 ASSERT (ProtocolGuid != NULL);\r
497\r
498 //\r
499 // Retrieve the list of agents that are consuming the specific protocol\r
500 // on ControllerHandle.\r
501 //\r
502 Status = gBS->OpenProtocolInformation (\r
503 ControllerHandle,\r
504 (EFI_GUID *) ProtocolGuid,\r
505 &OpenInfoBuffer,\r
506 &EntryCount\r
507 );\r
508 if (EFI_ERROR (Status)) {\r
509 return EFI_UNSUPPORTED;\r
510 }\r
511\r
512 //\r
513 // Inspect if ChildHandle is one of the agents.\r
514 //\r
515 Status = EFI_UNSUPPORTED;\r
516 for (Index = 0; Index < EntryCount; Index++) {\r
517 if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&\r
518 (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
519 Status = EFI_SUCCESS;\r
520 break;\r
521 }\r
522 }\r
523\r
524 FreePool (OpenInfoBuffer);\r
525 return Status;\r
526}\r
527\r
528/**\r
dd51a993 529 This function looks up a Unicode string in UnicodeStringTable.\r
530 If Language is a member of SupportedLanguages and a Unicode\r
531 string is found in UnicodeStringTable that matches the\r
532 language code specified by Language, then it is returned in\r
e386b444 533 UnicodeString.\r
534\r
dd51a993 535 @param Language A pointer to the ISO 639-2\r
536 language code for the Unicode\r
537 string to look up and return.\r
538 \r
539 @param SupportedLanguages A pointer to the set of ISO\r
540 639-2language\r
541 codes that the Unicode string\r
542 table supports. Language must\r
543 be a member of this set.\r
544 \r
545 @param UnicodeStringTable A pointer to the table of\r
546 Unicode strings.\r
547 \r
548 @param UnicodeString A pointer to the Unicode\r
549 string from UnicodeStringTable\r
550 that matches the language\r
551 specified by Language.\r
552\r
553 @retval EFI_SUCCESS The Unicode string that\r
554 matches the language specified\r
555 by Language was found in the\r
556 table of Unicoide strings\r
557 UnicodeStringTable, and it was\r
558 returned in UnicodeString.\r
559 \r
e386b444 560 @retval EFI_INVALID_PARAMETER Language is NULL.\r
dd51a993 561 \r
e386b444 562 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.\r
563 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.\r
dd51a993 564 \r
e386b444 565 @retval EFI_UNSUPPORTED UnicodeStringTable is NULL.\r
dd51a993 566 \r
567 @retval EFI_UNSUPPORTED The language specified by\r
568 Language is not a member\r
569 ofSupportedLanguages.\r
570 \r
571 @retval EFI_UNSUPPORTED The language specified by\r
572 Language is not supported by\r
573 UnicodeStringTable.\r
e386b444 574\r
575**/\r
576EFI_STATUS\r
577EFIAPI\r
578LookupUnicodeString (\r
579 IN CONST CHAR8 *Language,\r
580 IN CONST CHAR8 *SupportedLanguages,\r
581 IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable,\r
582 OUT CHAR16 **UnicodeString\r
583 )\r
584{\r
585 //\r
586 // Make sure the parameters are valid\r
587 //\r
588 if (Language == NULL || UnicodeString == NULL) {\r
589 return EFI_INVALID_PARAMETER;\r
590 }\r
591\r
592 //\r
593 // If there are no supported languages, or the Unicode String Table is empty, then the\r
594 // Unicode String specified by Language is not supported by this Unicode String Table\r
595 //\r
596 if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {\r
597 return EFI_UNSUPPORTED;\r
598 }\r
599\r
600 //\r
601 // Make sure Language is in the set of Supported Languages\r
602 //\r
603 while (*SupportedLanguages != 0) {\r
604 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {\r
605\r
606 //\r
607 // Search the Unicode String Table for the matching Language specifier\r
608 //\r
609 while (UnicodeStringTable->Language != NULL) {\r
610 if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {\r
611\r
612 //\r
613 // A matching string was found, so return it\r
614 //\r
615 *UnicodeString = UnicodeStringTable->UnicodeString;\r
616 return EFI_SUCCESS;\r
617 }\r
618\r
619 UnicodeStringTable++;\r
620 }\r
621\r
622 return EFI_UNSUPPORTED;\r
623 }\r
624\r
625 SupportedLanguages += 3;\r
626 }\r
627\r
628 return EFI_UNSUPPORTED;\r
629}\r
630\r
dd51a993 631\r
632\r
e386b444 633/**\r
dd51a993 634 This function looks up a Unicode string in UnicodeStringTable.\r
635 If Language is a member of SupportedLanguages and a Unicode\r
636 string is found in UnicodeStringTable that matches the\r
637 language code specified by Language, then it is returned in\r
638 UnicodeString.\r
639\r
640 @param Language A pointer to the ISO 639-2 or\r
641 RFC 3066 language code for the\r
642 Unicode string to look up and\r
643 return.\r
644 \r
645 @param SupportedLanguages A pointer to the set of ISO\r
646 639-2 or RFC 3066 language\r
647 codes that the Unicode string\r
648 table supports. Language must\r
649 be a member of this set.\r
650 \r
651 @param UnicodeStringTable A pointer to the table of\r
652 Unicode strings.\r
653 \r
654 @param UnicodeString A pointer to the Unicode\r
655 string from UnicodeStringTable\r
656 that matches the language\r
657 specified by Language.\r
658\r
659 @param Iso639Language Specify the language code\r
660 format supported. If true,\r
661 then the format follow ISO\r
662 639-2. If false, then it\r
663 follows RFC3066.\r
664\r
665 @retval EFI_SUCCESS The Unicode string that\r
666 matches the language specified\r
667 by Language was found in the\r
668 table of Unicoide strings\r
669 UnicodeStringTable, and it was\r
670 returned in UnicodeString.\r
671 \r
672 @retval EFI_INVALID_PARAMETER Language is NULL.\r
673 \r
674 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.\r
675 \r
676 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.\r
677 \r
678 @retval EFI_UNSUPPORTED UnicodeStringTable is NULL.\r
679 \r
680 @retval EFI_UNSUPPORTED The language specified by\r
681 Language is not a member\r
682 ofSupportedLanguages.\r
683 \r
684 @retval EFI_UNSUPPORTED The language specified by\r
685 Language is not supported by\r
686 UnicodeStringTable.\r
687\r
688**/\r
689EFI_STATUS\r
9edc73ad 690\r
dd51a993 691EFIAPI\r
692LookupUnicodeString2 (\r
693 IN CONST CHAR8 *Language,\r
694 IN CONST CHAR8 *SupportedLanguages,\r
695 IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable,\r
696 OUT CHAR16 **UnicodeString,\r
697 IN BOOLEAN Iso639Language\r
698 )\r
699{\r
700 BOOLEAN Found;\r
701 UINTN Index;\r
702 CHAR8 *LanguageString;\r
703\r
704 //\r
705 // Make sure the parameters are valid\r
706 //\r
707 if (Language == NULL || UnicodeString == NULL) {\r
708 return EFI_INVALID_PARAMETER;\r
709 }\r
710\r
711 //\r
712 // If there are no supported languages, or the Unicode String Table is empty, then the\r
713 // Unicode String specified by Language is not supported by this Unicode String Table\r
714 //\r
715 if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {\r
716 return EFI_UNSUPPORTED;\r
717 }\r
718\r
719 //\r
720 // Make sure Language is in the set of Supported Languages\r
721 //\r
722 Found = FALSE;\r
723 while (*SupportedLanguages != 0) {\r
724 if (Iso639Language) {\r
725 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {\r
726 Found = TRUE;\r
727 break;\r
728 }\r
729 SupportedLanguages += 3;\r
730 } else {\r
731 for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);\r
634aa59d 732 if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {\r
dd51a993 733 Found = TRUE;\r
734 break;\r
735 }\r
736 SupportedLanguages += Index;\r
737 for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);\r
738 }\r
739 }\r
740\r
741 //\r
742 // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED\r
743 //\r
744 if (!Found) {\r
745 return EFI_UNSUPPORTED;\r
746 }\r
747\r
748 //\r
749 // Search the Unicode String Table for the matching Language specifier\r
750 //\r
751 while (UnicodeStringTable->Language != NULL) {\r
752 LanguageString = UnicodeStringTable->Language;\r
753 while (0 != *LanguageString) {\r
754 for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);\r
755 if (AsciiStrnCmp(LanguageString, Language, Index) == 0) {\r
756 *UnicodeString = UnicodeStringTable->UnicodeString;\r
757 return EFI_SUCCESS;\r
758 }\r
759 LanguageString += Index;\r
760 for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++);\r
761 }\r
762 UnicodeStringTable++;\r
763 }\r
764\r
765 return EFI_UNSUPPORTED;\r
766}\r
767\r
768\r
769/**\r
770 \r
e386b444 771 This function adds a Unicode string to UnicodeStringTable.\r
dd51a993 772 If Language is a member of SupportedLanguages then\r
773 UnicodeString is added to UnicodeStringTable. New buffers are\r
774 allocated for both Language and UnicodeString. The contents\r
775 of Language and UnicodeString are copied into these new\r
776 buffers. These buffers are automatically freed when\r
e386b444 777 FreeUnicodeStringTable() is called.\r
778\r
dd51a993 779 @param Language A pointer to the ISO 639-2\r
780 language code for the Unicode\r
e386b444 781 string to add.\r
dd51a993 782 \r
783 @param SupportedLanguages A pointer to the set of ISO\r
784 639-2 language codes that the\r
785 Unicode string table supports.\r
786 Language must be a member of\r
787 this set.\r
788 \r
789 @param UnicodeStringTable A pointer to the table of\r
790 Unicode strings.\r
791 \r
792 @param UnicodeString A pointer to the Unicode\r
793 string to add.\r
794\r
795 @retval EFI_SUCCESS The Unicode string that\r
796 matches the language specified\r
797 by Language was found in the\r
798 table of Unicode strings\r
799 UnicodeStringTable, and it was\r
e386b444 800 returned in UnicodeString.\r
dd51a993 801 \r
e386b444 802 @retval EFI_INVALID_PARAMETER Language is NULL.\r
dd51a993 803 \r
e386b444 804 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.\r
dd51a993 805 \r
e386b444 806 @retval EFI_INVALID_PARAMETER UnicodeString is an empty string.\r
dd51a993 807 \r
e386b444 808 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.\r
dd51a993 809 \r
810 @retval EFI_ALREADY_STARTED A Unicode string with language\r
811 Language is already present in\r
812 UnicodeStringTable.\r
813 \r
814 @retval EFI_OUT_OF_RESOURCES There is not enough memory to\r
815 add another Unicode string to\r
816 UnicodeStringTable.\r
817 \r
818 @retval EFI_UNSUPPORTED The language specified by\r
819 Language is not a member of\r
820 SupportedLanguages.\r
e386b444 821\r
822**/\r
823EFI_STATUS\r
824EFIAPI\r
825AddUnicodeString (\r
826 IN CONST CHAR8 *Language,\r
827 IN CONST CHAR8 *SupportedLanguages,\r
828 IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable,\r
829 IN CONST CHAR16 *UnicodeString\r
830 )\r
831{\r
832 UINTN NumberOfEntries;\r
833 EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable;\r
834 EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable;\r
835 UINTN UnicodeStringLength;\r
836\r
837 //\r
838 // Make sure the parameter are valid\r
839 //\r
840 if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {\r
841 return EFI_INVALID_PARAMETER;\r
842 }\r
843\r
844 //\r
845 // If there are no supported languages, then a Unicode String can not be added\r
846 //\r
847 if (SupportedLanguages == NULL) {\r
848 return EFI_UNSUPPORTED;\r
849 }\r
850\r
851 //\r
852 // If the Unicode String is empty, then a Unicode String can not be added\r
853 //\r
854 if (UnicodeString[0] == 0) {\r
855 return EFI_INVALID_PARAMETER;\r
856 }\r
857\r
858 //\r
859 // Make sure Language is a member of SupportedLanguages\r
860 //\r
861 while (*SupportedLanguages != 0) {\r
862 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {\r
863\r
864 //\r
865 // Determine the size of the Unicode String Table by looking for a NULL Language entry\r
866 //\r
867 NumberOfEntries = 0;\r
868 if (*UnicodeStringTable != NULL) {\r
869 OldUnicodeStringTable = *UnicodeStringTable;\r
870 while (OldUnicodeStringTable->Language != NULL) {\r
871 if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {\r
872 return EFI_ALREADY_STARTED;\r
873 }\r
874\r
875 OldUnicodeStringTable++;\r
876 NumberOfEntries++;\r
877 }\r
878 }\r
879\r
880 //\r
881 // Allocate space for a new Unicode String Table. It must hold the current number of\r
882 // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table\r
883 // marker\r
884 //\r
885 NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));\r
886 if (NewUnicodeStringTable == NULL) {\r
887 return EFI_OUT_OF_RESOURCES;\r
888 }\r
889\r
890 //\r
891 // If the current Unicode String Table contains any entries, then copy them to the\r
892 // newly allocated Unicode String Table.\r
893 //\r
894 if (*UnicodeStringTable != NULL) {\r
895 CopyMem (\r
896 NewUnicodeStringTable,\r
897 *UnicodeStringTable,\r
898 NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)\r
899 );\r
900 }\r
901\r
902 //\r
903 // Allocate space for a copy of the Language specifier\r
904 //\r
905 NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);\r
906 if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {\r
907 gBS->FreePool (NewUnicodeStringTable);\r
908 return EFI_OUT_OF_RESOURCES;\r
909 }\r
910\r
911 //\r
912 // Compute the length of the Unicode String\r
913 //\r
914 for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)\r
915 ;\r
916\r
917 //\r
918 // Allocate space for a copy of the Unicode String\r
919 //\r
920 NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (\r
921 (UnicodeStringLength + 1) * sizeof (CHAR16),\r
922 UnicodeString\r
923 );\r
924 if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {\r
925 gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);\r
926 gBS->FreePool (NewUnicodeStringTable);\r
927 return EFI_OUT_OF_RESOURCES;\r
928 }\r
929\r
930 //\r
931 // Mark the end of the Unicode String Table\r
932 //\r
933 NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL;\r
934 NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;\r
935\r
936 //\r
937 // Free the old Unicode String Table\r
938 //\r
939 if (*UnicodeStringTable != NULL) {\r
940 gBS->FreePool (*UnicodeStringTable);\r
941 }\r
942\r
943 //\r
944 // Point UnicodeStringTable at the newly allocated Unicode String Table\r
945 //\r
946 *UnicodeStringTable = NewUnicodeStringTable;\r
947\r
948 return EFI_SUCCESS;\r
949 }\r
950\r
951 SupportedLanguages += 3;\r
952 }\r
953\r
954 return EFI_UNSUPPORTED;\r
955}\r
956\r
dd51a993 957\r
958/**\r
959 \r
960 This function adds a Unicode string to UnicodeStringTable.\r
961 If Language is a member of SupportedLanguages then\r
962 UnicodeString is added to UnicodeStringTable. New buffers are\r
963 allocated for both Language and UnicodeString. The contents\r
964 of Language and UnicodeString are copied into these new\r
965 buffers. These buffers are automatically freed when\r
966 FreeUnicodeStringTable() is called.\r
967\r
968 @param Language A pointer to the ISO 639-2 or\r
969 RFC 3066 language code for the\r
970 Unicode string to add.\r
971 \r
972 @param SupportedLanguages A pointer to the set of ISO\r
973 639-2 or RFC 3.66 language\r
974 codes that the Unicode string\r
975 table supports. Language must\r
976 be a member of this set.\r
977 \r
978 @param UnicodeStringTable A pointer to the table of\r
979 Unicode strings.\r
980 \r
981 @param UnicodeString A pointer to the Unicode\r
982 string to add.\r
983 \r
984 @param Iso639Language Specify the language code\r
985 format supported. If true,\r
986 then the format follow ISO\r
987 639-2. If false, then it\r
988 follows RFC3066.\r
989\r
990 @retval EFI_SUCCESS The Unicode string that\r
991 matches the language specified\r
992 by Language was found in the\r
993 table of Unicode strings\r
994 UnicodeStringTable, and it was\r
995 returned in UnicodeString.\r
996 \r
997 @retval EFI_INVALID_PARAMETER Language is NULL.\r
998 \r
999 @retval EFI_INVALID_PARAMETER UnicodeString is NULL.\r
1000 \r
1001 @retval EFI_INVALID_PARAMETER UnicodeString is an empty string.\r
1002 \r
1003 @retval EFI_UNSUPPORTED SupportedLanguages is NULL.\r
1004 \r
1005 @retval EFI_ALREADY_STARTED A Unicode string with language\r
1006 Language is already present in\r
1007 UnicodeStringTable.\r
1008 \r
1009 @retval EFI_OUT_OF_RESOURCES There is not enough memory to\r
1010 add another Unicode string to\r
1011 UnicodeStringTable.\r
1012 \r
1013 @retval EFI_UNSUPPORTED The language specified by\r
1014 Language is not a member of\r
1015 SupportedLanguages.\r
1016\r
1017**/\r
1018EFI_STATUS\r
1019EFIAPI\r
1020AddUnicodeString2 (\r
1021 IN CONST CHAR8 *Language,\r
1022 IN CONST CHAR8 *SupportedLanguages,\r
1023 IN EFI_UNICODE_STRING_TABLE **UnicodeStringTable,\r
1024 IN CONST CHAR16 *UnicodeString,\r
1025 IN BOOLEAN Iso639Language\r
1026 )\r
1027{\r
1028 UINTN NumberOfEntries;\r
1029 EFI_UNICODE_STRING_TABLE *OldUnicodeStringTable;\r
1030 EFI_UNICODE_STRING_TABLE *NewUnicodeStringTable;\r
1031 UINTN UnicodeStringLength;\r
1032 BOOLEAN Found;\r
1033 UINTN Index;\r
1034 CHAR8 *LanguageString;\r
1035\r
1036 //\r
1037 // Make sure the parameter are valid\r
1038 //\r
1039 if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {\r
1040 return EFI_INVALID_PARAMETER;\r
1041 }\r
1042\r
1043 //\r
1044 // If there are no supported languages, then a Unicode String can not be added\r
1045 //\r
1046 if (SupportedLanguages == NULL) {\r
1047 return EFI_UNSUPPORTED;\r
1048 }\r
1049\r
1050 //\r
1051 // If the Unicode String is empty, then a Unicode String can not be added\r
1052 //\r
1053 if (UnicodeString[0] == 0) {\r
1054 return EFI_INVALID_PARAMETER;\r
1055 }\r
1056\r
1057 //\r
1058 // Make sure Language is a member of SupportedLanguages\r
1059 //\r
1060 Found = FALSE;\r
1061 while (*SupportedLanguages != 0) {\r
1062 if (Iso639Language) {\r
1063 if (CompareIso639LanguageCode (Language, SupportedLanguages)) {\r
1064 Found = TRUE;\r
1065 break;\r
1066 }\r
1067 SupportedLanguages += 3;\r
1068 } else {\r
1069 for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);\r
1070 if (AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) {\r
1071 Found = TRUE;\r
1072 break;\r
1073 }\r
1074 SupportedLanguages += Index;\r
1075 for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);\r
1076 }\r
1077 }\r
1078\r
1079 //\r
1080 // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED\r
1081 //\r
1082 if (!Found) {\r
1083 return EFI_UNSUPPORTED;\r
1084 }\r
1085\r
1086 //\r
1087 // Determine the size of the Unicode String Table by looking for a NULL Language entry\r
1088 //\r
1089 NumberOfEntries = 0;\r
1090 if (*UnicodeStringTable != NULL) {\r
1091 OldUnicodeStringTable = *UnicodeStringTable;\r
1092 while (OldUnicodeStringTable->Language != NULL) {\r
1093 LanguageString = OldUnicodeStringTable->Language;\r
1094\r
42eedea9 1095 while (*LanguageString != 0) {\r
dd51a993 1096 for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);\r
1097\r
1098 if (AsciiStrnCmp (Language, LanguageString, Index) == 0) { \r
1099 return EFI_ALREADY_STARTED;\r
1100 }\r
1101 LanguageString += Index;\r
1102 for (; *LanguageString != 0 && *LanguageString == ';'; LanguageString++);\r
1103 }\r
1104 OldUnicodeStringTable++;\r
1105 NumberOfEntries++;\r
1106 }\r
1107 }\r
1108\r
1109 //\r
1110 // Allocate space for a new Unicode String Table. It must hold the current number of\r
1111 // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table\r
1112 // marker\r
1113 //\r
1114 NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));\r
1115 if (NewUnicodeStringTable == NULL) {\r
1116 return EFI_OUT_OF_RESOURCES;\r
1117 }\r
1118\r
1119 //\r
1120 // If the current Unicode String Table contains any entries, then copy them to the\r
1121 // newly allocated Unicode String Table.\r
1122 //\r
1123 if (*UnicodeStringTable != NULL) {\r
1124 CopyMem (\r
1125 NewUnicodeStringTable,\r
1126 *UnicodeStringTable,\r
1127 NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)\r
1128 );\r
1129 }\r
1130\r
1131 //\r
1132 // Allocate space for a copy of the Language specifier\r
1133 //\r
1134 NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize(Language), Language);\r
1135 if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {\r
1136 gBS->FreePool (NewUnicodeStringTable);\r
1137 return EFI_OUT_OF_RESOURCES;\r
1138 }\r
1139\r
1140 //\r
1141 // Compute the length of the Unicode String\r
1142 //\r
1143 for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++);\r
1144\r
1145 //\r
1146 // Allocate space for a copy of the Unicode String\r
1147 //\r
1148 NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString);\r
1149 if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {\r
1150 gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);\r
1151 gBS->FreePool (NewUnicodeStringTable);\r
1152 return EFI_OUT_OF_RESOURCES;\r
1153 }\r
1154\r
1155 //\r
1156 // Mark the end of the Unicode String Table\r
1157 //\r
1158 NewUnicodeStringTable[NumberOfEntries + 1].Language = NULL;\r
1159 NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;\r
1160\r
1161 //\r
1162 // Free the old Unicode String Table\r
1163 //\r
1164 if (*UnicodeStringTable != NULL) {\r
1165 gBS->FreePool (*UnicodeStringTable);\r
1166 }\r
1167\r
1168 //\r
1169 // Point UnicodeStringTable at the newly allocated Unicode String Table\r
1170 //\r
1171 *UnicodeStringTable = NewUnicodeStringTable;\r
1172\r
1173 return EFI_SUCCESS;\r
1174}\r
1175\r
e386b444 1176/**\r
1177 This function frees the table of Unicode strings in UnicodeStringTable.\r
1178 If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.\r
dd51a993 1179 Otherwise, each language code, and each Unicode string in the Unicode string \r
e386b444 1180 table are freed, and EFI_SUCCESS is returned.\r
1181\r
1182 @param UnicodeStringTable A pointer to the table of Unicode strings.\r
1183\r
1184 @retval EFI_SUCCESS The Unicode string table was freed.\r
1185\r
1186**/\r
1187EFI_STATUS\r
1188EFIAPI\r
1189FreeUnicodeStringTable (\r
1190 IN EFI_UNICODE_STRING_TABLE *UnicodeStringTable\r
1191 )\r
1192{\r
1193 UINTN Index;\r
1194\r
1195 //\r
1196 // If the Unicode String Table is NULL, then it is already freed\r
1197 //\r
1198 if (UnicodeStringTable == NULL) {\r
1199 return EFI_SUCCESS;\r
1200 }\r
1201\r
1202 //\r
1203 // Loop through the Unicode String Table until we reach the end of table marker\r
1204 //\r
1205 for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {\r
1206\r
1207 //\r
1208 // Free the Language string from the Unicode String Table\r
1209 //\r
1210 gBS->FreePool (UnicodeStringTable[Index].Language);\r
1211\r
1212 //\r
1213 // Free the Unicode String from the Unicode String Table\r
1214 //\r
1215 if (UnicodeStringTable[Index].UnicodeString != NULL) {\r
1216 gBS->FreePool (UnicodeStringTable[Index].UnicodeString);\r
1217 }\r
1218 }\r
1219\r
1220 //\r
1221 // Free the Unicode String Table itself\r
1222 //\r
1223 gBS->FreePool (UnicodeStringTable);\r
1224\r
1225 return EFI_SUCCESS;\r
1226}\r
1227\r
f8d18bad 1228/**\r
1229 Determine what is the current language setting. The space reserved for Lang\r
1230 must be at least RFC_3066_ENTRY_SIZE bytes;\r
1231\r
1232 If Lang is NULL, then ASSERT.\r
1233\r
1234 @param Lang Pointer of system language. Lang will always be filled with \r
1235 a valid RFC 3066 language string. If "PlatformLang" is not\r
1236 set in the system, the default language specifed by PcdUefiVariableDefaultPlatformLang\r
1237 is returned.\r
1238\r
1239 @return EFI_SUCCESS If the EFI Variable with "PlatformLang" is set and return in Lang.\r
1240 @return EFI_NOT_FOUND If the EFI Variable with "PlatformLang" is not set, but a valid default language is return in Lang.\r
1241\r
1242**/\r
1243EFI_STATUS\r
1244EFIAPI\r
1245GetCurrentLanguage (\r
1246 OUT CHAR8 *Lang\r
1247 )\r
1248{\r
1249 EFI_STATUS Status;\r
1250 UINTN Size;\r
1251\r
1252 ASSERT (Lang != NULL);\r
1253\r
1254 //\r
1255 // Get current language setting\r
1256 //\r
1257 Size = RFC_3066_ENTRY_SIZE;\r
1258 Status = gRT->GetVariable (\r
1259 L"PlatformLang",\r
1260 &gEfiGlobalVariableGuid,\r
1261 NULL,\r
1262 &Size,\r
1263 Lang\r
1264 );\r
1265\r
1266 if (EFI_ERROR (Status)) {\r
1267 AsciiStrCpy (Lang, (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang));\r
1268 }\r
1269\r
1270 return Status;\r
1271}\r
1272\r
1273\r
1c280088 1274\r