]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Hand/Locate.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Hand / Locate.c
... / ...
CommitLineData
1/** @file\r
2 Locate handle functions\r
3\r
4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "DxeMain.h"\r
16#include "Handle.h"\r
17\r
18//\r
19// ProtocolRequest - Last LocateHandle request ID\r
20//\r
21UINTN mEfiLocateHandleRequest = 0;\r
22\r
23//\r
24// Internal prototypes\r
25//\r
26\r
27typedef struct {\r
28 EFI_GUID *Protocol;\r
29 VOID *SearchKey;\r
30 LIST_ENTRY *Position;\r
31 PROTOCOL_ENTRY *ProtEntry;\r
32} LOCATE_POSITION;\r
33\r
34typedef\r
35IHANDLE *\r
36(* CORE_GET_NEXT) (\r
37 IN OUT LOCATE_POSITION *Position,\r
38 OUT VOID **Interface\r
39 );\r
40\r
41/**\r
42 Routine to get the next Handle, when you are searching for all handles.\r
43\r
44 @param Position Information about which Handle to seach for.\r
45 @param Interface Return the interface structure for the matching\r
46 protocol.\r
47\r
48 @return An pointer to IHANDLE if the next Position is not the end of the list.\r
49 Otherwise,NULL is returned.\r
50\r
51**/\r
52IHANDLE *\r
53CoreGetNextLocateAllHandles (\r
54 IN OUT LOCATE_POSITION *Position,\r
55 OUT VOID **Interface\r
56 );\r
57\r
58/**\r
59 Routine to get the next Handle, when you are searching for register protocol\r
60 notifies.\r
61\r
62 @param Position Information about which Handle to seach for.\r
63 @param Interface Return the interface structure for the matching\r
64 protocol.\r
65\r
66 @return An pointer to IHANDLE if the next Position is not the end of the list.\r
67 Otherwise,NULL is returned.\r
68\r
69**/\r
70IHANDLE *\r
71CoreGetNextLocateByRegisterNotify (\r
72 IN OUT LOCATE_POSITION *Position,\r
73 OUT VOID **Interface\r
74 );\r
75\r
76/**\r
77 Routine to get the next Handle, when you are searching for a given protocol.\r
78\r
79 @param Position Information about which Handle to seach for.\r
80 @param Interface Return the interface structure for the matching\r
81 protocol.\r
82\r
83 @return An pointer to IHANDLE if the next Position is not the end of the list.\r
84 Otherwise,NULL is returned.\r
85\r
86**/\r
87IHANDLE *\r
88CoreGetNextLocateByProtocol (\r
89 IN OUT LOCATE_POSITION *Position,\r
90 OUT VOID **Interface\r
91 );\r
92\r
93\r
94/**\r
95 Locates the requested handle(s) and returns them in Buffer.\r
96\r
97 @param SearchType The type of search to perform to locate the\r
98 handles\r
99 @param Protocol The protocol to search for\r
100 @param SearchKey Dependant on SearchType\r
101 @param BufferSize On input the size of Buffer. On output the\r
102 size of data returned.\r
103 @param Buffer The buffer to return the results in\r
104\r
105 @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is\r
106 returned in BufferSize.\r
107 @retval EFI_INVALID_PARAMETER Invalid parameter\r
108 @retval EFI_SUCCESS Successfully found the requested handle(s) and\r
109 returns them in Buffer.\r
110\r
111**/\r
112EFI_STATUS\r
113EFIAPI\r
114CoreLocateHandle (\r
115 IN EFI_LOCATE_SEARCH_TYPE SearchType,\r
116 IN EFI_GUID *Protocol OPTIONAL,\r
117 IN VOID *SearchKey OPTIONAL,\r
118 IN OUT UINTN *BufferSize,\r
119 OUT EFI_HANDLE *Buffer\r
120 )\r
121{\r
122 EFI_STATUS Status;\r
123 LOCATE_POSITION Position;\r
124 PROTOCOL_NOTIFY *ProtNotify;\r
125 CORE_GET_NEXT GetNext;\r
126 UINTN ResultSize;\r
127 IHANDLE *Handle;\r
128 IHANDLE **ResultBuffer;\r
129 VOID *Interface;\r
130\r
131 if (BufferSize == NULL) {\r
132 return EFI_INVALID_PARAMETER;\r
133 }\r
134\r
135 if ((*BufferSize > 0) && (Buffer == NULL)) {\r
136 return EFI_INVALID_PARAMETER;\r
137 }\r
138\r
139 GetNext = NULL;\r
140\r
141 //\r
142 // Set initial position\r
143 //\r
144 Position.Protocol = Protocol;\r
145 Position.SearchKey = SearchKey;\r
146 Position.Position = &gHandleList;\r
147\r
148 ResultSize = 0;\r
149 ResultBuffer = (IHANDLE **) Buffer;\r
150 Status = EFI_SUCCESS;\r
151\r
152 //\r
153 // Lock the protocol database\r
154 //\r
155 CoreAcquireProtocolLock ();\r
156\r
157 //\r
158 // Get the search function based on type\r
159 //\r
160 switch (SearchType) {\r
161 case AllHandles:\r
162 GetNext = CoreGetNextLocateAllHandles;\r
163 break;\r
164\r
165 case ByRegisterNotify:\r
166 //\r
167 // Must have SearchKey for locate ByRegisterNotify\r
168 //\r
169 if (SearchKey == NULL) {\r
170 Status = EFI_INVALID_PARAMETER;\r
171 break;\r
172 }\r
173 GetNext = CoreGetNextLocateByRegisterNotify;\r
174 break;\r
175\r
176 case ByProtocol:\r
177 GetNext = CoreGetNextLocateByProtocol;\r
178 if (Protocol == NULL) {\r
179 Status = EFI_INVALID_PARAMETER;\r
180 break;\r
181 }\r
182 //\r
183 // Look up the protocol entry and set the head pointer\r
184 //\r
185 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);\r
186 if (Position.ProtEntry == NULL) {\r
187 Status = EFI_NOT_FOUND;\r
188 break;\r
189 }\r
190 Position.Position = &Position.ProtEntry->Protocols;\r
191 break;\r
192\r
193 default:\r
194 Status = EFI_INVALID_PARAMETER;\r
195 break;\r
196 }\r
197\r
198 if (EFI_ERROR(Status)) {\r
199 CoreReleaseProtocolLock ();\r
200 return Status;\r
201 }\r
202\r
203 ASSERT (GetNext != NULL);\r
204 //\r
205 // Enumerate out the matching handles\r
206 //\r
207 mEfiLocateHandleRequest += 1;\r
208 for (; ;) {\r
209 //\r
210 // Get the next handle. If no more handles, stop\r
211 //\r
212 Handle = GetNext (&Position, &Interface);\r
213 if (NULL == Handle) {\r
214 break;\r
215 }\r
216\r
217 //\r
218 // Increase the resulting buffer size, and if this handle\r
219 // fits return it\r
220 //\r
221 ResultSize += sizeof(Handle);\r
222 if (ResultSize <= *BufferSize) {\r
223 *ResultBuffer = Handle;\r
224 ResultBuffer += 1;\r
225 }\r
226 }\r
227\r
228 //\r
229 // If the result is a zero length buffer, then there were no\r
230 // matching handles\r
231 //\r
232 if (ResultSize == 0) {\r
233 Status = EFI_NOT_FOUND;\r
234 } else {\r
235 //\r
236 // Return the resulting buffer size. If it's larger than what\r
237 // was passed, then set the error code\r
238 //\r
239 if (ResultSize > *BufferSize) {\r
240 Status = EFI_BUFFER_TOO_SMALL;\r
241 }\r
242\r
243 *BufferSize = ResultSize;\r
244\r
245 if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {\r
246 //\r
247 // If this is a search by register notify and a handle was\r
248 // returned, update the register notification position\r
249 //\r
250 ASSERT (SearchKey != NULL);\r
251 ProtNotify = SearchKey;\r
252 ProtNotify->Position = ProtNotify->Position->ForwardLink;\r
253 }\r
254 }\r
255\r
256 CoreReleaseProtocolLock ();\r
257 return Status;\r
258}\r
259\r
260\r
261\r
262/**\r
263 Routine to get the next Handle, when you are searching for all handles.\r
264\r
265 @param Position Information about which Handle to seach for.\r
266 @param Interface Return the interface structure for the matching\r
267 protocol.\r
268\r
269 @return An pointer to IHANDLE if the next Position is not the end of the list.\r
270 Otherwise,NULL is returned.\r
271\r
272**/\r
273IHANDLE *\r
274CoreGetNextLocateAllHandles (\r
275 IN OUT LOCATE_POSITION *Position,\r
276 OUT VOID **Interface\r
277 )\r
278{\r
279 IHANDLE *Handle;\r
280\r
281 //\r
282 // Next handle\r
283 //\r
284 Position->Position = Position->Position->ForwardLink;\r
285\r
286 //\r
287 // If not at the end of the list, get the handle\r
288 //\r
289 Handle = NULL;\r
290 *Interface = NULL;\r
291 if (Position->Position != &gHandleList) {\r
292 Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);\r
293 }\r
294\r
295 return Handle;\r
296}\r
297\r
298\r
299\r
300/**\r
301 Routine to get the next Handle, when you are searching for register protocol\r
302 notifies.\r
303\r
304 @param Position Information about which Handle to seach for.\r
305 @param Interface Return the interface structure for the matching\r
306 protocol.\r
307\r
308 @return An pointer to IHANDLE if the next Position is not the end of the list.\r
309 Otherwise,NULL is returned.\r
310\r
311**/\r
312IHANDLE *\r
313CoreGetNextLocateByRegisterNotify (\r
314 IN OUT LOCATE_POSITION *Position,\r
315 OUT VOID **Interface\r
316 )\r
317{\r
318 IHANDLE *Handle;\r
319 PROTOCOL_NOTIFY *ProtNotify;\r
320 PROTOCOL_INTERFACE *Prot;\r
321 LIST_ENTRY *Link;\r
322\r
323 Handle = NULL;\r
324 *Interface = NULL;\r
325 ProtNotify = Position->SearchKey;\r
326\r
327 //\r
328 // If this is the first request, get the next handle\r
329 //\r
330 if (ProtNotify != NULL) {\r
331 ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);\r
332 Position->SearchKey = NULL;\r
333\r
334 //\r
335 // If not at the end of the list, get the next handle\r
336 //\r
337 Link = ProtNotify->Position->ForwardLink;\r
338 if (Link != &ProtNotify->Protocol->Protocols) {\r
339 Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);\r
340 Handle = Prot->Handle;\r
341 *Interface = Prot->Interface;\r
342 }\r
343 }\r
344\r
345 return Handle;\r
346}\r
347\r
348\r
349/**\r
350 Routine to get the next Handle, when you are searching for a given protocol.\r
351\r
352 @param Position Information about which Handle to seach for.\r
353 @param Interface Return the interface structure for the matching\r
354 protocol.\r
355\r
356 @return An pointer to IHANDLE if the next Position is not the end of the list.\r
357 Otherwise,NULL is returned.\r
358\r
359**/\r
360IHANDLE *\r
361CoreGetNextLocateByProtocol (\r
362 IN OUT LOCATE_POSITION *Position,\r
363 OUT VOID **Interface\r
364 )\r
365{\r
366 IHANDLE *Handle;\r
367 LIST_ENTRY *Link;\r
368 PROTOCOL_INTERFACE *Prot;\r
369\r
370 Handle = NULL;\r
371 *Interface = NULL;\r
372 for (; ;) {\r
373 //\r
374 // Next entry\r
375 //\r
376 Link = Position->Position->ForwardLink;\r
377 Position->Position = Link;\r
378\r
379 //\r
380 // If not at the end, return the handle\r
381 //\r
382 if (Link == &Position->ProtEntry->Protocols) {\r
383 Handle = NULL;\r
384 break;\r
385 }\r
386\r
387 //\r
388 // Get the handle\r
389 //\r
390 Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);\r
391 Handle = Prot->Handle;\r
392 *Interface = Prot->Interface;\r
393\r
394 //\r
395 // If this handle has not been returned this request, then\r
396 // return it now\r
397 //\r
398 if (Handle->LocateRequest != mEfiLocateHandleRequest) {\r
399 Handle->LocateRequest = mEfiLocateHandleRequest;\r
400 break;\r
401 }\r
402 }\r
403\r
404 return Handle;\r
405}\r
406\r
407\r
408/**\r
409 Locates the handle to a device on the device path that supports the specified protocol.\r
410\r
411 @param Protocol Specifies the protocol to search for.\r
412 @param DevicePath On input, a pointer to a pointer to the device path. On output, the device\r
413 path pointer is modified to point to the remaining part of the device\r
414 path.\r
415 @param Device A pointer to the returned device handle.\r
416\r
417 @retval EFI_SUCCESS The resulting handle was returned.\r
418 @retval EFI_NOT_FOUND No handles match the search.\r
419 @retval EFI_INVALID_PARAMETER Protocol is NULL.\r
420 @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
421 @retval EFI_INVALID_PARAMETER A handle matched the search and Device is NULL.\r
422\r
423**/\r
424EFI_STATUS\r
425EFIAPI\r
426CoreLocateDevicePath (\r
427 IN EFI_GUID *Protocol,\r
428 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,\r
429 OUT EFI_HANDLE *Device\r
430 )\r
431{\r
432 INTN SourceSize;\r
433 INTN Size;\r
434 INTN BestMatch;\r
435 UINTN HandleCount;\r
436 UINTN Index;\r
437 EFI_STATUS Status;\r
438 EFI_HANDLE *Handles;\r
439 EFI_HANDLE Handle;\r
440 EFI_HANDLE BestDevice;\r
441 EFI_DEVICE_PATH_PROTOCOL *SourcePath;\r
442 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r
443\r
444 if (Protocol == NULL) {\r
445 return EFI_INVALID_PARAMETER;\r
446 }\r
447\r
448 if ((DevicePath == NULL) || (*DevicePath == NULL)) {\r
449 return EFI_INVALID_PARAMETER;\r
450 }\r
451\r
452 Handles = NULL;\r
453 BestDevice = NULL;\r
454 SourcePath = *DevicePath;\r
455 TmpDevicePath = SourcePath;\r
456 while (!IsDevicePathEnd (TmpDevicePath)) {\r
457 if (IsDevicePathEndInstance (TmpDevicePath)) {\r
458 //\r
459 // If DevicePath is a multi-instance device path,\r
460 // the function will operate on the first instance\r
461 //\r
462 break;\r
463 }\r
464 TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r
465 }\r
466\r
467 SourceSize = (UINTN) TmpDevicePath - (UINTN) SourcePath;\r
468\r
469 //\r
470 // Get a list of all handles that support the requested protocol\r
471 //\r
472 Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles);\r
473 if (EFI_ERROR (Status) || HandleCount == 0) {\r
474 return EFI_NOT_FOUND;\r
475 }\r
476\r
477 BestMatch = -1;\r
478 for(Index = 0; Index < HandleCount; Index += 1) {\r
479 Handle = Handles[Index];\r
480 Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&TmpDevicePath);\r
481 if (EFI_ERROR (Status)) {\r
482 //\r
483 // If this handle doesn't support device path, then skip it\r
484 //\r
485 continue;\r
486 }\r
487\r
488 //\r
489 // Check if DevicePath is first part of SourcePath\r
490 //\r
491 Size = GetDevicePathSize (TmpDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
492 ASSERT (Size >= 0);\r
493 if ((Size <= SourceSize) && CompareMem (SourcePath, TmpDevicePath, (UINTN) Size) == 0) {\r
494 //\r
495 // If the size is equal to the best match, then we\r
496 // have a duplicate device path for 2 different device\r
497 // handles\r
498 //\r
499 ASSERT (Size != BestMatch);\r
500\r
501 //\r
502 // We've got a match, see if it's the best match so far\r
503 //\r
504 if (Size > BestMatch) {\r
505 BestMatch = Size;\r
506 BestDevice = Handle;\r
507 }\r
508 }\r
509 }\r
510\r
511 CoreFreePool (Handles);\r
512\r
513 //\r
514 // If there wasn't any match, then no parts of the device path was found.\r
515 // Which is strange since there is likely a "root level" device path in the system.\r
516 //\r
517 if (BestMatch == -1) {\r
518 return EFI_NOT_FOUND;\r
519 }\r
520\r
521 if (Device == NULL) {\r
522 return EFI_INVALID_PARAMETER;\r
523 }\r
524 *Device = BestDevice;\r
525\r
526 //\r
527 // Return the remaining part of the device path\r
528 //\r
529 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) SourcePath) + BestMatch);\r
530 return EFI_SUCCESS;\r
531}\r
532\r
533\r
534/**\r
535 Return the first Protocol Interface that matches the Protocol GUID. If\r
536 Registration is passed in, return a Protocol Instance that was just add\r
537 to the system. If Registration is NULL return the first Protocol Interface\r
538 you find.\r
539\r
540 @param Protocol The protocol to search for\r
541 @param Registration Optional Registration Key returned from\r
542 RegisterProtocolNotify()\r
543 @param Interface Return the Protocol interface (instance).\r
544\r
545 @retval EFI_SUCCESS If a valid Interface is returned\r
546 @retval EFI_INVALID_PARAMETER Invalid parameter\r
547 @retval EFI_NOT_FOUND Protocol interface not found\r
548\r
549**/\r
550EFI_STATUS\r
551EFIAPI\r
552CoreLocateProtocol (\r
553 IN EFI_GUID *Protocol,\r
554 IN VOID *Registration OPTIONAL,\r
555 OUT VOID **Interface\r
556 )\r
557{\r
558 EFI_STATUS Status;\r
559 LOCATE_POSITION Position;\r
560 PROTOCOL_NOTIFY *ProtNotify;\r
561 IHANDLE *Handle;\r
562\r
563 if ((Interface == NULL) || (Protocol == NULL)) {\r
564 return EFI_INVALID_PARAMETER;\r
565 }\r
566\r
567 *Interface = NULL;\r
568 Status = EFI_SUCCESS;\r
569\r
570 //\r
571 // Set initial position\r
572 //\r
573 Position.Protocol = Protocol;\r
574 Position.SearchKey = Registration;\r
575 Position.Position = &gHandleList;\r
576\r
577 //\r
578 // Lock the protocol database\r
579 //\r
580 Status = CoreAcquireLockOrFail (&gProtocolDatabaseLock);\r
581 if (EFI_ERROR (Status)) {\r
582 return EFI_NOT_FOUND;\r
583 }\r
584\r
585 mEfiLocateHandleRequest += 1;\r
586\r
587 if (Registration == NULL) {\r
588 //\r
589 // Look up the protocol entry and set the head pointer\r
590 //\r
591 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);\r
592 if (Position.ProtEntry == NULL) {\r
593 Status = EFI_NOT_FOUND;\r
594 goto Done;\r
595 }\r
596 Position.Position = &Position.ProtEntry->Protocols;\r
597\r
598 Handle = CoreGetNextLocateByProtocol (&Position, Interface);\r
599 } else {\r
600 Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);\r
601 }\r
602\r
603 if (Handle == NULL) {\r
604 Status = EFI_NOT_FOUND;\r
605 } else if (Registration != NULL) {\r
606 //\r
607 // If this is a search by register notify and a handle was\r
608 // returned, update the register notification position\r
609 //\r
610 ProtNotify = Registration;\r
611 ProtNotify->Position = ProtNotify->Position->ForwardLink;\r
612 }\r
613\r
614Done:\r
615 CoreReleaseProtocolLock ();\r
616 return Status;\r
617}\r
618\r
619\r
620/**\r
621 Function returns an array of handles that support the requested protocol\r
622 in a buffer allocated from pool. This is a version of CoreLocateHandle()\r
623 that allocates a buffer for the caller.\r
624\r
625 @param SearchType Specifies which handle(s) are to be returned.\r
626 @param Protocol Provides the protocol to search by. This\r
627 parameter is only valid for SearchType\r
628 ByProtocol.\r
629 @param SearchKey Supplies the search key depending on the\r
630 SearchType.\r
631 @param NumberHandles The number of handles returned in Buffer.\r
632 @param Buffer A pointer to the buffer to return the requested\r
633 array of handles that support Protocol.\r
634\r
635 @retval EFI_SUCCESS The result array of handles was returned.\r
636 @retval EFI_NOT_FOUND No handles match the search.\r
637 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the\r
638 matching results.\r
639 @retval EFI_INVALID_PARAMETER One or more parameters are not valid.\r
640\r
641**/\r
642EFI_STATUS\r
643EFIAPI\r
644CoreLocateHandleBuffer (\r
645 IN EFI_LOCATE_SEARCH_TYPE SearchType,\r
646 IN EFI_GUID *Protocol OPTIONAL,\r
647 IN VOID *SearchKey OPTIONAL,\r
648 IN OUT UINTN *NumberHandles,\r
649 OUT EFI_HANDLE **Buffer\r
650 )\r
651{\r
652 EFI_STATUS Status;\r
653 UINTN BufferSize;\r
654\r
655 if (NumberHandles == NULL) {\r
656 return EFI_INVALID_PARAMETER;\r
657 }\r
658\r
659 if (Buffer == NULL) {\r
660 return EFI_INVALID_PARAMETER;\r
661 }\r
662\r
663 BufferSize = 0;\r
664 *NumberHandles = 0;\r
665 *Buffer = NULL;\r
666 Status = CoreLocateHandle (\r
667 SearchType,\r
668 Protocol,\r
669 SearchKey,\r
670 &BufferSize,\r
671 *Buffer\r
672 );\r
673 //\r
674 // LocateHandleBuffer() returns incorrect status code if SearchType is\r
675 // invalid.\r
676 //\r
677 // Add code to correctly handle expected errors from CoreLocateHandle().\r
678 //\r
679 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
680 if (Status != EFI_INVALID_PARAMETER) {\r
681 Status = EFI_NOT_FOUND;\r
682 }\r
683 return Status;\r
684 }\r
685\r
686 *Buffer = AllocatePool (BufferSize);\r
687 if (*Buffer == NULL) {\r
688 return EFI_OUT_OF_RESOURCES;\r
689 }\r
690\r
691 Status = CoreLocateHandle (\r
692 SearchType,\r
693 Protocol,\r
694 SearchKey,\r
695 &BufferSize,\r
696 *Buffer\r
697 );\r
698\r
699 *NumberHandles = BufferSize / sizeof(EFI_HANDLE);\r
700 if (EFI_ERROR(Status)) {\r
701 *NumberHandles = 0;\r
702 }\r
703\r
704 return Status;\r
705}\r
706\r
707\r
708\r