Home | History | Annotate | Download | only in WinNtBusDriverDxe
      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
    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 *
    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
    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
    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
    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 *
    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