1 /**@file
2 
3 Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
4 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   WinNtBusDriver.c
15 
16 Abstract:
17 
18 This following section documents the envirnoment variables for the Win NT
19 build.  These variables are used to define the (virtual) hardware
20 configuration of the NT environment
21 
22 A ! can be used to seperate multiple instances in a variable. Each
23 instance represents a seperate hardware device.
24 
25 EFI_WIN_NT_PHYSICAL_DISKS - maps to drives on your system
26 EFI_WIN_NT_VIRTUAL_DISKS  - maps to a device emulated by a file
27 EFI_WIN_NT_FILE_SYSTEM    - mouts a directory as a file system
28 EFI_WIN_NT_CONSOLE        - make a logical comand line window (only one!)
29 EFI_WIN_NT_GOP            - Builds GOP Windows of Width and Height
30 EFI_WIN_NT_SERIAL_PORT    - maps physical serial ports
31 
32  <F>ixed       - Fixed disk like a hard drive.
33  <R>emovable   - Removable media like a floppy or CD-ROM.
34  Read <O>nly   - Write protected device.
35  Read <W>rite  - Read write device.
36  <block count> - Decimal number of blocks a device supports.
37  <block size>  - Decimal number of bytes per block.
38 
39  NT envirnonment variable contents. '<' and '>' are not part of the variable,
40  they are just used to make this help more readable. There should be no
41  spaces between the ';'. Extra spaces will break the variable. A '!' is
42  used to seperate multiple devices in a variable.
43 
44  EFI_WIN_NT_VIRTUAL_DISKS =
45    <F | R><O | W>;<block count>;<block size>[!...]
46 
47  EFI_WIN_NT_PHYSICAL_DISKS =
48    <drive letter>:<F | R><O | W>;<block count>;<block size>[!...]
49 
50  Virtual Disks: These devices use a file to emulate a hard disk or removable
51                 media device.
52 
53    Thus a 20 MB emulated hard drive would look like:
54    EFI_WIN_NT_VIRTUAL_DISKS=FW;40960;512
55 
56    A 1.44MB emulated floppy with a block size of 1024 would look like:
57    EFI_WIN_NT_VIRTUAL_DISKS=RW;1440;1024
58 
59  Physical Disks: These devices use NT to open a real device in your system
60 
61    Thus a 120 MB floppy would look like:
62    EFI_WIN_NT_PHYSICAL_DISKS=B:RW;245760;512
63 
64    Thus a standard CD-ROM floppy would look like:
65    EFI_WIN_NT_PHYSICAL_DISKS=Z:RO;307200;2048
66 
67  EFI_WIN_NT_FILE_SYSTEM =
68    <directory path>[!...]
69 
70    Mounting the two directories C:\FOO and C:\BAR would look like:
71    EFI_WIN_NT_FILE_SYSTEM=c:\foo!c:\bar
72 
73  EFI_WIN_NT_CONSOLE =
74    <window title>
75 
76    Declaring a text console window with the title "My EFI Console" woild look like:
77    EFI_WIN_NT_CONSOLE=My EFI Console
78 
79  EFI_WIN_NT_GOP =
80    <width> <height>[!...]
81 
82    Declaring a two GOP windows with resolutions of 800x600 and 1024x768 would look like:
83    Example : EFI_WIN_NT_GOP=800 600!1024 768
84 
85  EFI_WIN_NT_SERIAL_PORT =
86    <port name>[!...]
87 
88    Declaring two serial ports on COM1 and COM2 would look like:
89    Example : EFI_WIN_NT_SERIAL_PORT=COM1!COM2
90 
91  EFI_WIN_NT_PASS_THROUGH =
92    <BaseAddress>;<Bus#>;<Device#>;<Function#>
93 
94    Declaring a base address of 0xE0000000 (used for PCI Express devices)
95    and having NT32 talk to a device located at bus 0, device 1, function 0:
96    Example : EFI_WIN_NT_PASS_THROUGH=E000000;0;1;0
97 
98 ---*/
99 
100 //
101 // The package level header files this module uses
102 //
103 #include <Uefi.h>
104 #include <WinNtDxe.h>
105 //
106 // The protocols, PPI and GUID defintions for this module
107 //
108 #include <Protocol/WinNtThunk.h>
109 #include <Protocol/WinNtIo.h>
110 #include <Protocol/ComponentName.h>
111 #include <Protocol/DriverBinding.h>
112 #include <Protocol/DevicePath.h>
113 //
114 // The Library classes this module consumes
115 //
116 #include <Library/DebugLib.h>
117 #include <Library/BaseLib.h>
118 #include <Library/UefiDriverEntryPoint.h>
119 #include <Library/UefiLib.h>
120 #include <Library/PcdLib.h>
121 #include <Library/BaseMemoryLib.h>
122 #include <Library/UefiBootServicesTableLib.h>
123 #include <Library/DevicePathLib.h>
124 #include <Library/MemoryAllocationLib.h>
125 
126 #include "WinNtBusDriver.h"
127 
128 extern EFI_GUID gWinNtBusDriverGuid;
129 //
130 // DriverBinding protocol global
131 //
132 EFI_DRIVER_BINDING_PROTOCOL           gWinNtBusDriverBinding = {
133   WinNtBusDriverBindingSupported,
134   WinNtBusDriverBindingStart,
135   WinNtBusDriverBindingStop,
136   0xa,
137   NULL,
138   NULL
139 };
140 
141 #define NT_PCD_ARRAY_SIZE (sizeof(mPcdEnvironment)/sizeof(NT_PCD_ENTRY))
142 
143 //
144 // Table to map NT Environment variable to the GUID that should be in
145 // device path.
146 //
147 NT_PCD_ENTRY  mPcdEnvironment[] = {
148   PcdToken(PcdWinNtConsole),       &gEfiWinNtConsoleGuid,
149   PcdToken(PcdWinNtGop),           &gEfiWinNtGopGuid,
150   PcdToken(PcdWinNtSerialPort),    &gEfiWinNtSerialPortGuid,
151   PcdToken(PcdWinNtFileSystem),    &gEfiWinNtFileSystemGuid,
152   PcdToken(PcdWinNtVirtualDisk),   &gEfiWinNtVirtualDisksGuid,
153   PcdToken(PcdWinNtPhysicalDisk),  &gEfiWinNtPhysicalDisksGuid
154 };
155 
156 /**
157   The user Entry Point for module WinNtBusDriver. The user code starts with this function.
158 
159   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
160   @param[in] SystemTable    A pointer to the EFI System Table.
161 
162   @retval EFI_SUCCESS       The entry point is executed successfully.
163   @retval other             Some error occurs when executing this entry point.
164 
165 **/
166 EFI_STATUS
167 EFIAPI
InitializeWinNtBusDriver(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)168 InitializeWinNtBusDriver(
169   IN EFI_HANDLE           ImageHandle,
170   IN EFI_SYSTEM_TABLE     *SystemTable
171   )
172 {
173   EFI_STATUS              Status;
174 
175   //
176   // Install driver model protocol(s).
177   //
178   Status = EfiLibInstallDriverBindingComponentName2 (
179              ImageHandle,
180              SystemTable,
181              &gWinNtBusDriverBinding,
182              ImageHandle,
183              &gWinNtBusDriverComponentName,
184              &gWinNtBusDriverComponentName2
185              );
186   ASSERT_EFI_ERROR (Status);
187 
188 
189   return Status;
190 }
191 
192 VOID *
AllocateMemory(IN UINTN Size)193 AllocateMemory (
194   IN  UINTN   Size
195   )
196 {
197   VOID        *Buffer;
198 
199   Buffer = AllocatePool (Size);
200   ASSERT (Buffer != NULL);
201 
202   return Buffer;
203 }
204 
205 
206 EFI_STATUS
207 EFIAPI
WinNtBusDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)208 WinNtBusDriverBindingSupported (
209   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
210   IN  EFI_HANDLE                   ControllerHandle,
211   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
212   )
213 /*++
214 
215 Routine Description:
216 
217 Arguments:
218 
219 Returns:
220 
221   None
222 
223 **/
224 // TODO:    This - add argument and description to function comment
225 // TODO:    ControllerHandle - add argument and description to function comment
226 // TODO:    RemainingDevicePath - add argument and description to function comment
227 // TODO:    EFI_UNSUPPORTED - add return value to function comment
228 // TODO:    EFI_UNSUPPORTED - add return value to function comment
229 // TODO:    EFI_SUCCESS - add return value to function comment
230 // TODO:    EFI_SUCCESS - add return value to function comment
231 {
232   EFI_STATUS                Status;
233   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
234   EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk;
235   UINTN                     Index;
236 
237   //
238   // Check the contents of the first Device Path Node of RemainingDevicePath to make sure
239   // it is a legal Device Path Node for this bus driver's children.
240   //
241   if (RemainingDevicePath != NULL) {
242     //
243     // Check if RemainingDevicePath is the End of Device Path Node,
244     // if yes, go on checking other conditions
245     //
246     if (!IsDevicePathEnd (RemainingDevicePath)) {
247       //
248       // If RemainingDevicePath isn't the End of Device Path Node,
249       // check its validation
250       //
251       if (RemainingDevicePath->Type != HARDWARE_DEVICE_PATH ||
252           RemainingDevicePath->SubType != HW_VENDOR_DP ||
253           DevicePathNodeLength(RemainingDevicePath) != sizeof(WIN_NT_VENDOR_DEVICE_PATH_NODE)) {
254         return EFI_UNSUPPORTED;
255       }
256 
257       for (Index = 0; Index < NT_PCD_ARRAY_SIZE; Index++) {
258         if (CompareGuid (&((VENDOR_DEVICE_PATH *) RemainingDevicePath)->Guid, mPcdEnvironment[Index].DevicePathGuid)) {
259           break;
260         }
261       }
262 
263       if (Index >= NT_PCD_ARRAY_SIZE) {
264         return EFI_UNSUPPORTED;
265       }
266     }
267   }
268 
269   //
270   // Open the IO Abstraction(s) needed to perform the supported test
271   //
272   Status = gBS->OpenProtocol (
273                   ControllerHandle,
274                   &gEfiWinNtThunkProtocolGuid,
275                   (VOID **) &WinNtThunk,
276                   This->DriverBindingHandle,
277                   ControllerHandle,
278                   EFI_OPEN_PROTOCOL_BY_DRIVER
279                   );
280   if (Status == EFI_ALREADY_STARTED) {
281     return EFI_SUCCESS;
282   }
283 
284   if (EFI_ERROR (Status)) {
285     return Status;
286   }
287 
288   //
289   // Close the I/O Abstraction(s) used to perform the supported test
290   //
291   gBS->CloseProtocol (
292         ControllerHandle,
293         &gEfiWinNtThunkProtocolGuid,
294         This->DriverBindingHandle,
295         ControllerHandle
296         );
297 
298   //
299   // Open the EFI Device Path protocol needed to perform the supported test
300   //
301   Status = gBS->OpenProtocol (
302                   ControllerHandle,
303                   &gEfiDevicePathProtocolGuid,
304                   (VOID **) &ParentDevicePath,
305                   This->DriverBindingHandle,
306                   ControllerHandle,
307                   EFI_OPEN_PROTOCOL_BY_DRIVER
308                   );
309   if (Status == EFI_ALREADY_STARTED) {
310     return EFI_SUCCESS;
311   }
312 
313   if (EFI_ERROR (Status)) {
314     return Status;
315   }
316 
317   //
318   // Since we call through WinNtThunk we need to make sure it's valid
319   //
320   Status = EFI_SUCCESS;
321   if (WinNtThunk->Signature != EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) {
322     Status = EFI_UNSUPPORTED;
323   }
324 
325   //
326   // Close protocol, don't use device path protocol in the Support() function
327   //
328   gBS->CloseProtocol (
329         ControllerHandle,
330         &gEfiDevicePathProtocolGuid,
331         This->DriverBindingHandle,
332         ControllerHandle
333         );
334 
335   return Status;
336 }
337 
338 EFI_STATUS
339 EFIAPI
WinNtBusDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)340 WinNtBusDriverBindingStart (
341   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
342   IN  EFI_HANDLE                   ControllerHandle,
343   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
344   )
345 /*++
346 
347 Routine Description:
348 
349 Arguments:
350 
351 Returns:
352 
353   None
354 
355 --*/
356 // TODO:    This - add argument and description to function comment
357 // TODO:    ControllerHandle - add argument and description to function comment
358 // TODO:    RemainingDevicePath - add argument and description to function comment
359 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
360 // TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
361 // TODO:    EFI_SUCCESS - add return value to function comment
362 {
363   EFI_STATUS                      Status;
364   EFI_WIN_NT_THUNK_PROTOCOL       *WinNtThunk;
365   EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;
366   WIN_NT_BUS_DEVICE               *WinNtBusDevice;
367   WIN_NT_IO_DEVICE                *WinNtDevice;
368   UINTN                           Index;
369   CHAR16                          *StartString;
370   CHAR16                          *SubString;
371   UINT16                          Count;
372   UINTN                           StringSize;
373   UINT16                          ComponentName[MAX_NT_ENVIRNMENT_VARIABLE_LENGTH];
374   WIN_NT_VENDOR_DEVICE_PATH_NODE  *Node;
375   BOOLEAN                         CreateDevice;
376   CHAR16                          *TempStr;
377   CHAR16                          *PcdTempStr;
378   UINTN                           TempStrSize;
379 
380   Status = EFI_UNSUPPORTED;
381 
382   //
383   // Grab the protocols we need
384   //
385   Status = gBS->OpenProtocol (
386                   ControllerHandle,
387                   &gEfiDevicePathProtocolGuid,
388                   (VOID **) &ParentDevicePath,
389                   This->DriverBindingHandle,
390                   ControllerHandle,
391                   EFI_OPEN_PROTOCOL_BY_DRIVER
392                   );
393   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
394     return Status;
395   }
396 
397   Status = gBS->OpenProtocol (
398                   ControllerHandle,
399                   &gEfiWinNtThunkProtocolGuid,
400                   (VOID **) &WinNtThunk,
401                   This->DriverBindingHandle,
402                   ControllerHandle,
403                   EFI_OPEN_PROTOCOL_BY_DRIVER
404                   );
405   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
406     return Status;
407   }
408 
409   if (Status != EFI_ALREADY_STARTED) {
410     WinNtBusDevice = AllocatePool (sizeof (WIN_NT_BUS_DEVICE));
411     if (WinNtBusDevice == NULL) {
412       return EFI_OUT_OF_RESOURCES;
413     }
414 
415     WinNtBusDevice->Signature           = WIN_NT_BUS_DEVICE_SIGNATURE;
416     WinNtBusDevice->ControllerNameTable = NULL;
417 
418     AddUnicodeString2 (
419       "eng",
420       gWinNtBusDriverComponentName.SupportedLanguages,
421       &WinNtBusDevice->ControllerNameTable,
422       L"Windows Bus Controller",
423       TRUE
424       );
425     AddUnicodeString2 (
426       "en",
427       gWinNtBusDriverComponentName2.SupportedLanguages,
428       &WinNtBusDevice->ControllerNameTable,
429       L"Windows Bus Controller",
430       FALSE
431       );
432 
433 
434     Status = gBS->InstallMultipleProtocolInterfaces (
435                     &ControllerHandle,
436                     &gWinNtBusDriverGuid,
437                     WinNtBusDevice,
438                     NULL
439                     );
440     if (EFI_ERROR (Status)) {
441       FreeUnicodeStringTable (WinNtBusDevice->ControllerNameTable);
442       FreePool (WinNtBusDevice);
443       return Status;
444     }
445   }
446 
447   //
448   // Loop on the Variable list. Parse each variable to produce a set of handles that
449   // represent virtual hardware devices.
450   //
451   for (Index = 0; Index < NT_PCD_ARRAY_SIZE; Index++) {
452     PcdTempStr = (VOID *)LibPcdGetPtr (mPcdEnvironment[Index].Token);
453     ASSERT (PcdTempStr != NULL);
454 
455     TempStrSize = StrLen (PcdTempStr);
456     TempStr = AllocateMemory ((TempStrSize * sizeof (CHAR16)) + 1);
457     StrCpy (TempStr, PcdTempStr);
458 
459     StartString = TempStr;
460 
461     //
462     // Parse the envirnment variable into sub strings using '!' as a delimator.
463     // Each substring needs it's own handle to be added to the system. This code
464     // does not understand the sub string. Thats the device drivers job.
465     //
466     Count = 0;
467     while (*StartString != '\0') {
468 
469       //
470       // Find the end of the sub string
471       //
472       SubString = StartString;
473       while (*SubString != '\0' && *SubString != '!') {
474         SubString++;
475       }
476 
477       if (*SubString == '!') {
478         //
479         // Replace token with '\0' to make sub strings. If this is the end
480         //  of the string SubString will already point to NULL.
481         //
482         *SubString = '\0';
483         SubString++;
484       }
485 
486       CreateDevice = TRUE;
487       if (RemainingDevicePath != NULL) {
488         CreateDevice  = FALSE;
489         //
490         // Check if RemainingDevicePath is the End of Device Path Node,
491         // if yes, don't create any child device
492         //
493         if (!IsDevicePathEnd (RemainingDevicePath)) {
494           //
495           // If RemainingDevicePath isn't the End of Device Path Node,
496           // check its validation
497           //
498           Node          = (WIN_NT_VENDOR_DEVICE_PATH_NODE *) RemainingDevicePath;
499           if (Node->VendorDevicePath.Header.Type == HARDWARE_DEVICE_PATH &&
500               Node->VendorDevicePath.Header.SubType == HW_VENDOR_DP &&
501               DevicePathNodeLength (&Node->VendorDevicePath.Header) == sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE)
502               ) {
503             if (CompareGuid (&Node->VendorDevicePath.Guid, mPcdEnvironment[Index].DevicePathGuid) &&
504                 Node->Instance == Count
505                 ) {
506               CreateDevice = TRUE;
507             }
508           }
509         }
510       }
511 
512       if (CreateDevice) {
513 
514         //
515         // Allocate instance structure, and fill in parent information.
516         //
517         WinNtDevice = AllocateMemory (sizeof (WIN_NT_IO_DEVICE));
518         if (WinNtDevice == NULL) {
519           return EFI_OUT_OF_RESOURCES;
520         }
521 
522         WinNtDevice->Handle             = NULL;
523         WinNtDevice->ControllerHandle   = ControllerHandle;
524         WinNtDevice->ParentDevicePath   = ParentDevicePath;
525 
526         WinNtDevice->WinNtIo.WinNtThunk = WinNtThunk;
527 
528         //
529         // Plus 2 to account for the NULL at the end of the Unicode string
530         //
531         StringSize = (UINTN) ((UINT8 *) SubString - (UINT8 *) StartString) + sizeof (CHAR16);
532         WinNtDevice->WinNtIo.EnvString = AllocateMemory (StringSize);
533         if (WinNtDevice->WinNtIo.EnvString != NULL) {
534           CopyMem (WinNtDevice->WinNtIo.EnvString, StartString, StringSize);
535         }
536 
537         WinNtDevice->ControllerNameTable = NULL;
538 
539         WinNtThunk->SPrintf (ComponentName, sizeof (ComponentName), L"%s", WinNtDevice->WinNtIo.EnvString);
540 
541         WinNtDevice->DevicePath = WinNtBusCreateDevicePath (
542                                     ParentDevicePath,
543                                     mPcdEnvironment[Index].DevicePathGuid,
544                                     Count
545                                     );
546         if (WinNtDevice->DevicePath == NULL) {
547           FreePool (WinNtDevice);
548           return EFI_OUT_OF_RESOURCES;
549         }
550 
551         AddUnicodeString2 (
552           "eng",
553           gWinNtBusDriverComponentName.SupportedLanguages,
554           &WinNtDevice->ControllerNameTable,
555           ComponentName,
556           TRUE
557           );
558         AddUnicodeString2 (
559           "en",
560           gWinNtBusDriverComponentName2.SupportedLanguages,
561           &WinNtDevice->ControllerNameTable,
562           ComponentName,
563           FALSE
564           );
565 
566 
567         WinNtDevice->WinNtIo.TypeGuid       = mPcdEnvironment[Index].DevicePathGuid;
568         WinNtDevice->WinNtIo.InstanceNumber = Count;
569 
570         WinNtDevice->Signature              = WIN_NT_IO_DEVICE_SIGNATURE;
571 
572         Status = gBS->InstallMultipleProtocolInterfaces (
573                         &WinNtDevice->Handle,
574                         &gEfiDevicePathProtocolGuid,
575                         WinNtDevice->DevicePath,
576                         &gEfiWinNtIoProtocolGuid,
577                         &WinNtDevice->WinNtIo,
578                         NULL
579                         );
580         if (EFI_ERROR (Status)) {
581           FreeUnicodeStringTable (WinNtDevice->ControllerNameTable);
582           FreePool (WinNtDevice);
583         } else {
584           //
585           // Open For Child Device
586           //
587           Status = gBS->OpenProtocol (
588                           ControllerHandle,
589                           &gEfiWinNtThunkProtocolGuid,
590                           (VOID **) &WinNtThunk,
591                           This->DriverBindingHandle,
592                           WinNtDevice->Handle,
593                           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
594                           );
595         }
596       }
597 
598       //
599       // Parse Next sub string. This will point to '\0' if we are at the end.
600       //
601       Count++;
602       StartString = SubString;
603     }
604 
605     FreePool (TempStr);
606   }
607 
608   return EFI_SUCCESS;
609 }
610 
611 
612 EFI_STATUS
613 EFIAPI
WinNtBusDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)614 WinNtBusDriverBindingStop (
615   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
616   IN  EFI_HANDLE                   ControllerHandle,
617   IN  UINTN                        NumberOfChildren,
618   IN  EFI_HANDLE                   *ChildHandleBuffer
619   )
620 /*++
621 
622 Routine Description:
623 
624 Arguments:
625 
626 Returns:
627 
628     None
629 
630 --*/
631 // TODO:    This - add argument and description to function comment
632 // TODO:    ControllerHandle - add argument and description to function comment
633 // TODO:    NumberOfChildren - add argument and description to function comment
634 // TODO:    ChildHandleBuffer - add argument and description to function comment
635 // TODO:    EFI_SUCCESS - add return value to function comment
636 // TODO:    EFI_DEVICE_ERROR - add return value to function comment
637 // TODO:    EFI_SUCCESS - add return value to function comment
638 {
639   EFI_STATUS                Status;
640   UINTN                     Index;
641   BOOLEAN                   AllChildrenStopped;
642   EFI_WIN_NT_IO_PROTOCOL    *WinNtIo;
643   WIN_NT_BUS_DEVICE         *WinNtBusDevice;
644   WIN_NT_IO_DEVICE          *WinNtDevice;
645   EFI_WIN_NT_THUNK_PROTOCOL *WinNtThunk;
646 
647   //
648   // Complete all outstanding transactions to Controller.
649   // Don't allow any new transaction to Controller to be started.
650   //
651 
652   if (NumberOfChildren == 0) {
653     //
654     // Close the bus driver
655     //
656     Status = gBS->OpenProtocol (
657                     ControllerHandle,
658                     &gWinNtBusDriverGuid,
659                     (VOID **) &WinNtBusDevice,
660                     This->DriverBindingHandle,
661                     ControllerHandle,
662                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
663                     );
664     if (EFI_ERROR (Status)) {
665       return Status;
666     }
667 
668     gBS->UninstallMultipleProtocolInterfaces (
669           ControllerHandle,
670           &gWinNtBusDriverGuid,
671           WinNtBusDevice,
672           NULL
673           );
674 
675     FreeUnicodeStringTable (WinNtBusDevice->ControllerNameTable);
676 
677     FreePool (WinNtBusDevice);
678 
679     gBS->CloseProtocol (
680           ControllerHandle,
681           &gEfiWinNtThunkProtocolGuid,
682           This->DriverBindingHandle,
683           ControllerHandle
684           );
685 
686     gBS->CloseProtocol (
687           ControllerHandle,
688           &gEfiDevicePathProtocolGuid,
689           This->DriverBindingHandle,
690           ControllerHandle
691           );
692     return EFI_SUCCESS;
693   }
694 
695   AllChildrenStopped = TRUE;
696 
697   for (Index = 0; Index < NumberOfChildren; Index++) {
698 
699     Status = gBS->OpenProtocol (
700                     ChildHandleBuffer[Index],
701                     &gEfiWinNtIoProtocolGuid,
702                     (VOID **) &WinNtIo,
703                     This->DriverBindingHandle,
704                     ControllerHandle,
705                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
706                     );
707     if (!EFI_ERROR (Status)) {
708 
709       WinNtDevice = WIN_NT_IO_DEVICE_FROM_THIS (WinNtIo);
710 
711       Status = gBS->CloseProtocol (
712                       ControllerHandle,
713                       &gEfiWinNtThunkProtocolGuid,
714                       This->DriverBindingHandle,
715                       WinNtDevice->Handle
716                       );
717 
718       Status = gBS->UninstallMultipleProtocolInterfaces (
719                       WinNtDevice->Handle,
720                       &gEfiDevicePathProtocolGuid,
721                       WinNtDevice->DevicePath,
722                       &gEfiWinNtIoProtocolGuid,
723                       &WinNtDevice->WinNtIo,
724                       NULL
725                       );
726 
727       if (EFI_ERROR (Status)) {
728         gBS->OpenProtocol (
729               ControllerHandle,
730               &gEfiWinNtThunkProtocolGuid,
731               (VOID **) &WinNtThunk,
732               This->DriverBindingHandle,
733               WinNtDevice->Handle,
734               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
735               );
736       } else {
737         //
738         // Close the child handle
739         //
740         FreeUnicodeStringTable (WinNtDevice->ControllerNameTable);
741         FreePool (WinNtDevice);
742       }
743     }
744 
745     if (EFI_ERROR (Status)) {
746       AllChildrenStopped = FALSE;
747     }
748   }
749 
750   if (!AllChildrenStopped) {
751     return EFI_DEVICE_ERROR;
752   }
753 
754   return EFI_SUCCESS;
755 }
756 
757 EFI_DEVICE_PATH_PROTOCOL *
WinNtBusCreateDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * RootDevicePath,IN EFI_GUID * Guid,IN UINT16 InstanceNumber)758 WinNtBusCreateDevicePath (
759   IN  EFI_DEVICE_PATH_PROTOCOL  *RootDevicePath,
760   IN  EFI_GUID                  *Guid,
761   IN  UINT16                    InstanceNumber
762   )
763 /*++
764 
765 Routine Description:
766   Create a device path node using Guid and InstanceNumber and append it to
767   the passed in RootDevicePath
768 
769 Arguments:
770   RootDevicePath - Root of the device path to return.
771 
772   Guid           - GUID to use in vendor device path node.
773 
774   InstanceNumber - Instance number to use in the vendor device path. This
775                     argument is needed to make sure each device path is unique.
776 
777 Returns:
778 
779   EFI_DEVICE_PATH_PROTOCOL
780 
781 --*/
782 {
783   WIN_NT_VENDOR_DEVICE_PATH_NODE  DevicePath;
784 
785   DevicePath.VendorDevicePath.Header.Type     = HARDWARE_DEVICE_PATH;
786   DevicePath.VendorDevicePath.Header.SubType  = HW_VENDOR_DP;
787   SetDevicePathNodeLength (&DevicePath.VendorDevicePath.Header, sizeof (WIN_NT_VENDOR_DEVICE_PATH_NODE));
788 
789   //
790   // The GUID defines the Class
791   //
792   CopyMem (&DevicePath.VendorDevicePath.Guid, Guid, sizeof (EFI_GUID));
793 
794   //
795   // Add an instance number so we can make sure there are no Device Path
796   // duplication.
797   //
798   DevicePath.Instance = InstanceNumber;
799 
800   return AppendDevicePathNode (
801           RootDevicePath,
802           (EFI_DEVICE_PATH_PROTOCOL *) &DevicePath
803           );
804 }
805