コード例 #1
0
ファイル: SerMode.c プロジェクト: OznOg/edk2
/**
  Function for 'sermode' command.

  @param[in] ImageHandle  Handle to the Image (NULL if Internal).
  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
**/
SHELL_STATUS
EFIAPI
ShellCommandRunSerMode (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS              Status;
  SHELL_STATUS            ShellStatus;
  UINTN                   Index;
  UINTN                   NoHandles;
  EFI_HANDLE              *Handles;
  EFI_PARITY_TYPE         Parity;
  EFI_STOP_BITS_TYPE      StopBits;
  UINTN                   HandleIdx;
  UINTN                   BaudRate;
  UINTN                   DataBits;
  UINTN                   Value;
  EFI_SERIAL_IO_PROTOCOL  *SerialIo;
  LIST_ENTRY              *Package;
  CHAR16                  *ProblemParam;
  CONST CHAR16            *Temp;
  UINT64                  Intermediate;

  ShellStatus = SHELL_SUCCESS;
  HandleIdx   = 0;
  Parity      = DefaultParity;
  Handles     = NULL;
  NoHandles   = 0;
  Index       = 0;
  Package     = NULL;

  Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);
  if (EFI_ERROR(Status)) {
    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"sermode", ProblemParam);  
      FreePool(ProblemParam);
      ShellStatus = SHELL_INVALID_PARAMETER;
    } else {
      ASSERT(FALSE);
    }
  } else {
    if (ShellCommandLineGetCount(Package) < 6 && ShellCommandLineGetCount(Package) > 2) {
      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"sermode");  
      ShellStatus = SHELL_INVALID_PARAMETER;
    } else if (ShellCommandLineGetCount(Package) > 6) {
      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"sermode");  
      ShellStatus = SHELL_INVALID_PARAMETER;
    } else {
      Temp = ShellCommandLineGetRawValue(Package, 1);
      if (Temp != NULL) {
        Status = ShellConvertStringToUint64(Temp, &Intermediate, TRUE, FALSE);
        HandleIdx = (UINTN)Intermediate;
        Temp = ShellCommandLineGetRawValue(Package, 2);
        if (Temp == NULL) {
          ShellStatus = DisplaySettings (HandleIdx, TRUE);
          goto Done;
        }
      } else {
        ShellStatus = DisplaySettings (0, FALSE);
        goto Done;
      }
      Temp = ShellCommandLineGetRawValue(Package, 2);
      if (Temp != NULL) {
        BaudRate = ShellStrToUintn(Temp);
      } else {
        ASSERT(FALSE);
        BaudRate = 0;
      }
      Temp = ShellCommandLineGetRawValue(Package, 3);
      if (Temp == NULL || StrLen(Temp)>1) {
        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"sermode", Temp);  
        ShellStatus = SHELL_INVALID_PARAMETER;
      } else {
        switch(Temp[0]){
        case 'd':
        case 'D':
          Parity = DefaultParity;
          break;
        case 'n':
        case 'N':
          Parity = NoParity;
          break;
        case 'e':
        case 'E':
          Parity = EvenParity;
          break;
        case 'o':
        case 'O':
          Parity = OddParity;
          break;
        case 'm':
        case 'M':
          Parity = MarkParity;
          break;
        case 's':
        case 'S':
          Parity = SpaceParity;
          break;
        default:
          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"sermode", Temp);  
          ShellStatus = SHELL_INVALID_PARAMETER;
          goto Done;
        }
      }
      Temp = ShellCommandLineGetRawValue(Package, 4);
      if (Temp != NULL) {
        DataBits = ShellStrToUintn(Temp);
      } else {
        //
        // make sure this is some number not in the list below.
        //
        DataBits = 0;
      }
      switch (DataBits) {
      case 4:
      case 7:
      case 8:
        break;
      default:
        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"sermode", Temp);  
        ShellStatus = SHELL_INVALID_PARAMETER;
        goto Done;
      }
      Temp = ShellCommandLineGetRawValue(Package, 5);
      Value = ShellStrToUintn(Temp);
      switch (Value) {
      case 0:
        StopBits = DefaultStopBits;
        break;

      case 1:
        StopBits = OneStopBit;
        break;

      case 2:
        StopBits = TwoStopBits;
        break;

      case 15:
        StopBits = OneFiveStopBits;
        break;

      default:
        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"sermode", Temp);  
        ShellStatus = SHELL_INVALID_PARAMETER;
        goto Done;
      }
      Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSerialIoProtocolGuid, NULL, &NoHandles, &Handles);
      if (EFI_ERROR (Status)) {
        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_NO_FOUND), gShellDebug1HiiHandle, L"sermode");  
        ShellStatus = SHELL_INVALID_PARAMETER;
        goto Done;
      }

      for (Index = 0; Index < NoHandles; Index++) {
        if (ConvertHandleIndexToHandle (HandleIdx) != Handles[Index]) {
          continue;
        }

        Status = gBS->HandleProtocol (Handles[Index], &gEfiSerialIoProtocolGuid, (VOID**)&SerialIo);
        if (!EFI_ERROR (Status)) {
          Status = SerialIo->SetAttributes (
                              SerialIo,
                              (UINT64) BaudRate,
                              SerialIo->Mode->ReceiveFifoDepth,
                              SerialIo->Mode->Timeout,
                              Parity,
                              (UINT8) DataBits,
                              StopBits
                             );
          if (EFI_ERROR (Status)) {
            if (Status == EFI_INVALID_PARAMETER) {
              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_SET_UNSUPPORTED), gShellDebug1HiiHandle, L"sermode", ConvertHandleToHandleIndex(Handles[Index]));  
              ShellStatus = SHELL_UNSUPPORTED;
            } else if (Status == EFI_DEVICE_ERROR) {
              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_SET_DEV_ERROR), gShellDebug1HiiHandle, L"sermode", ConvertHandleToHandleIndex(Handles[Index]));  
              ShellStatus = SHELL_ACCESS_DENIED;
            } else {
              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_SET_FAIL), gShellDebug1HiiHandle, L"sermode", ConvertHandleToHandleIndex(Handles[Index]));  
              ShellStatus = SHELL_ACCESS_DENIED;
            }
          } else {
            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_SET_HANDLE), gShellDebug1HiiHandle, ConvertHandleToHandleIndex(Handles[Index]));
          }
          break;
        }
      }
    }
  }

  if (ShellStatus == SHELL_SUCCESS && Index == NoHandles) {
    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SERMODE_BAD_HANDLE), gShellDebug1HiiHandle, L"sermode", HandleIdx);  
    ShellStatus = SHELL_INVALID_PARAMETER;
  }

Done:
  if (Package != NULL) {
    ShellCommandLineFreeVarList (Package);
  }
  if (Handles != NULL) {
    FreePool (Handles);
  }
  return ShellStatus;
}
コード例 #2
0
ファイル: WinNtSerialIo.c プロジェクト: Kohrara/edk
STATIC
EFI_STATUS
EFIAPI
WinNtSerialIoDriverBindingStart (
    IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
    IN  EFI_HANDLE                    Handle,
    IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
)
/*++

Routine Description:

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Handle - add argument and description to function comment
// TODO:    RemainingDevicePath - add argument and description to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
    EFI_STATUS                          Status;
    EFI_WIN_NT_IO_PROTOCOL              *WinNtIo;
    WIN_NT_SERIAL_IO_PRIVATE_DATA       *Private;
    HANDLE                              NtHandle;
    UART_DEVICE_PATH                    Node;
    EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
    EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
    UINTN                               EntryCount;
    UINTN                               Index;
    EFI_SERIAL_IO_PROTOCOL              *SerialIo;

    Private   = NULL;
    NtHandle  = INVALID_HANDLE_VALUE;

    //
    // Grab the protocols we need
    //
    Status = gBS->OpenProtocol (
                 Handle,
                 &gEfiDevicePathProtocolGuid,
                 &ParentDevicePath,
                 This->DriverBindingHandle,
                 Handle,
                 EFI_OPEN_PROTOCOL_BY_DRIVER
             );
    if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
        return Status;
    }

    //
    // Grab the IO abstraction we need to get any work done
    //
    Status = gBS->OpenProtocol (
                 Handle,
                 &gEfiWinNtIoProtocolGuid,
                 &WinNtIo,
                 This->DriverBindingHandle,
                 Handle,
                 EFI_OPEN_PROTOCOL_BY_DRIVER
             );
    if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
        gBS->CloseProtocol (
            Handle,
            &gEfiDevicePathProtocolGuid,
            This->DriverBindingHandle,
            Handle
        );
        return Status;
    }

    if (Status == EFI_ALREADY_STARTED) {

        if (RemainingDevicePath == NULL) {
            return EFI_SUCCESS;
        }

        //
        // Make sure a child handle does not already exist.  This driver can only
        // produce one child per serial port.
        //
        Status = gBS->OpenProtocolInformation (
                     Handle,
                     &gEfiWinNtIoProtocolGuid,
                     &OpenInfoBuffer,
                     &EntryCount
                 );
        if (EFI_ERROR (Status)) {
            return Status;
        }

        Status = EFI_ALREADY_STARTED;
        for (Index = 0; Index < EntryCount; Index++) {
            if (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
                Status = gBS->OpenProtocol (
                             OpenInfoBuffer[Index].ControllerHandle,
                             &gEfiSerialIoProtocolGuid,
                             &SerialIo,
                             This->DriverBindingHandle,
                             Handle,
                             EFI_OPEN_PROTOCOL_GET_PROTOCOL
                         );
                if (!EFI_ERROR (Status)) {
                    EfiCopyMem (&Node, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
                    Status = SerialIo->SetAttributes (
                                 SerialIo,
                                 Node.BaudRate,
                                 SerialIo->Mode->ReceiveFifoDepth,
                                 SerialIo->Mode->Timeout,
                                 Node.Parity,
                                 Node.DataBits,
                                 Node.StopBits
                             );
                }
                break;
            }
        }

        gBS->FreePool (OpenInfoBuffer);
        return Status;
    }

    //
    // Check to see if we can access the hardware device. If it's Open in NT we
    // will not get access.
    //
    NtHandle = WinNtIo->WinNtThunk->CreateFile (
                   WinNtIo->EnvString,
                   GENERIC_READ | GENERIC_WRITE,
                   0,
                   NULL,
                   OPEN_EXISTING,
                   0,
                   NULL
               );
    if (NtHandle == INVALID_HANDLE_VALUE) {
        Status = EFI_DEVICE_ERROR;
        goto Error;
    }

    //
    // Construct Private data
    //
    Status = gBS->AllocatePool (
                 EfiBootServicesData,
                 sizeof (WIN_NT_SERIAL_IO_PRIVATE_DATA),
                 &Private
             );
    if (EFI_ERROR (Status)) {
        goto Error;
    }

    //
    // This signature must be valid before any member function is called
    //
    Private->Signature              = WIN_NT_SERIAL_IO_PRIVATE_DATA_SIGNATURE;
    Private->NtHandle               = NtHandle;
    Private->ControllerHandle       = Handle;
    Private->Handle                 = NULL;
    Private->WinNtThunk             = WinNtIo->WinNtThunk;
    Private->ParentDevicePath       = ParentDevicePath;
    Private->ControllerNameTable    = NULL;

    Private->SoftwareLoopbackEnable = FALSE;
    Private->HardwareLoopbackEnable = FALSE;
    Private->HardwareFlowControl    = FALSE;
    Private->Fifo.First             = 0;
    Private->Fifo.Last              = 0;
    Private->Fifo.Surplus           = SERIAL_MAX_BUFFER_SIZE;

    EfiLibAddUnicodeString (
        LANGUAGE_CODE_ENGLISH,
        gWinNtSerialIoComponentName.SupportedLanguages,
        &Private->ControllerNameTable,
        WinNtIo->EnvString
    );

    Private->SerialIo.Revision      = SERIAL_IO_INTERFACE_REVISION;
    Private->SerialIo.Reset         = WinNtSerialIoReset;
    Private->SerialIo.SetAttributes = WinNtSerialIoSetAttributes;
    Private->SerialIo.SetControl    = WinNtSerialIoSetControl;
    Private->SerialIo.GetControl    = WinNtSerialIoGetControl;
    Private->SerialIo.Write         = WinNtSerialIoWrite;
    Private->SerialIo.Read          = WinNtSerialIoRead;
    Private->SerialIo.Mode          = &Private->SerialIoMode;

    if (RemainingDevicePath != NULL) {
        //
        // Match the configuration of the RemainingDevicePath. IsHandleSupported()
        // already checked to make sure the RemainingDevicePath contains settings
        // that we can support.
        //
        EfiCopyMem (&Private->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
    } else {
        //
        // Build the device path by appending the UART node to the ParentDevicePath
        // from the WinNtIo handle. The Uart setings are zero here, since
        // SetAttribute() will update them to match the default setings.
        //
        EfiZeroMem (&Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
        Private->UartDevicePath.Header.Type     = MESSAGING_DEVICE_PATH;
        Private->UartDevicePath.Header.SubType  = MSG_UART_DP;
        SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath, sizeof (UART_DEVICE_PATH));
    }

    //
    // Build the device path by appending the UART node to the ParentDevicePath
    // from the WinNtIo handle. The Uart setings are zero here, since
    // SetAttribute() will update them to match the current setings.
    //
    Private->DevicePath = EfiAppendDevicePathNode (
                              ParentDevicePath,
                              (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
                          );
    if (Private->DevicePath == NULL) {
        Status = EFI_OUT_OF_RESOURCES;
        goto Error;
    }

    //
    // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
    //
    Private->SerialIoMode.ControlMask       = SERIAL_CONTROL_MASK;
    Private->SerialIoMode.Timeout           = SERIAL_TIMEOUT_DEFAULT;
    Private->SerialIoMode.BaudRate          = Private->UartDevicePath.BaudRate;
    Private->SerialIoMode.ReceiveFifoDepth  = SERIAL_FIFO_DEFAULT;
    Private->SerialIoMode.DataBits          = Private->UartDevicePath.DataBits;
    Private->SerialIoMode.Parity            = Private->UartDevicePath.Parity;
    Private->SerialIoMode.StopBits          = Private->UartDevicePath.StopBits;

    //
    // Issue a reset to initialize the COM port
    //
    Status = Private->SerialIo.Reset (&Private->SerialIo);
    if (EFI_ERROR (Status)) {
        goto Error;
    }

    //
    // Create new child handle
    //
    Status = gBS->InstallMultipleProtocolInterfaces (
                 &Private->Handle,
                 &gEfiSerialIoProtocolGuid,
                 &Private->SerialIo,
                 &gEfiDevicePathProtocolGuid,
                 Private->DevicePath,
                 NULL
             );
    if (EFI_ERROR (Status)) {
        goto Error;
    }

    //
    // Open For Child Device
    //
    Status = gBS->OpenProtocol (
                 Handle,
                 &gEfiWinNtIoProtocolGuid,
                 &WinNtIo,
                 This->DriverBindingHandle,
                 Private->Handle,
                 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
             );
    if (EFI_ERROR (Status)) {
        goto Error;
    }

    return EFI_SUCCESS;

Error:
    //
    // Use the Stop() function to free all resources allocated in Start()
    //
    if (Private != NULL) {
        if (Private->Handle != NULL) {
            This->Stop (This, Handle, 1, &Private->Handle);
        } else {
            if (NtHandle != INVALID_HANDLE_VALUE) {
                Private->WinNtThunk->CloseHandle (NtHandle);
            }

            if (Private->DevicePath != NULL) {
                gBS->FreePool (Private->DevicePath);
            }

            EfiLibFreeUnicodeStringTable (Private->ControllerNameTable);

            gBS->FreePool (Private);
        }
    }

    This->Stop (This, Handle, 0, NULL);

    return Status;
}
コード例 #3
0
ファイル: TerminalConIn.c プロジェクト: B-Rich/edk2
/**
  Timer handler to poll the key from serial.

  @param  Event                    Indicates the event that invoke this function.
  @param  Context                  Indicates the calling context.
**/
VOID
EFIAPI
TerminalConInTimerHandler (
  IN EFI_EVENT            Event,
  IN VOID                 *Context
  )
{
  EFI_STATUS              Status;
  TERMINAL_DEV            *TerminalDevice;
  UINT32                  Control;
  UINT8                   Input;
  EFI_SERIAL_IO_MODE      *Mode;
  EFI_SERIAL_IO_PROTOCOL  *SerialIo;
  UINTN                   SerialInTimeOut;

  TerminalDevice  = (TERMINAL_DEV *) Context;

  SerialIo        = TerminalDevice->SerialIo;
  if (SerialIo == NULL) {
    return ;
  }
  //
  //  if current timeout value for serial device is not identical with
  //  the value saved in TERMINAL_DEV structure, then recalculate the
  //  timeout value again and set serial attribute according to this value.
  //
  Mode = SerialIo->Mode;
  if (Mode->Timeout != TerminalDevice->SerialInTimeOut) {

    SerialInTimeOut = 0;
    if (Mode->BaudRate != 0) {
      //
      // According to BAUD rate to calculate the timeout value.
      //
      SerialInTimeOut = (1 + Mode->DataBits + Mode->StopBits) * 2 * 1000000 / (UINTN) Mode->BaudRate;
    }

    Status = SerialIo->SetAttributes (
                        SerialIo,
                        Mode->BaudRate,
                        Mode->ReceiveFifoDepth,
                        (UINT32) SerialInTimeOut,
                        (EFI_PARITY_TYPE) (Mode->Parity),
                        (UINT8) Mode->DataBits,
                        (EFI_STOP_BITS_TYPE) (Mode->StopBits)
                        );

    if (EFI_ERROR (Status)) {
      TerminalDevice->SerialInTimeOut = 0;
    } else {
      TerminalDevice->SerialInTimeOut = SerialInTimeOut;
    }
  }
  //
  // Check whether serial buffer is empty.
  //
  Status = SerialIo->GetControl (SerialIo, &Control);

  if ((Control & EFI_SERIAL_INPUT_BUFFER_EMPTY) == 0) {
    //
    // Fetch all the keys in the serial buffer,
    // and insert the byte stream into RawFIFO.
    //
    while (!IsRawFiFoFull (TerminalDevice)) {

      Status = GetOneKeyFromSerial (TerminalDevice->SerialIo, &Input);

      if (EFI_ERROR (Status)) {
        if (Status == EFI_DEVICE_ERROR) {
          REPORT_STATUS_CODE_WITH_DEVICE_PATH (
            EFI_ERROR_CODE | EFI_ERROR_MINOR,
            (EFI_PERIPHERAL_REMOTE_CONSOLE | EFI_P_EC_INPUT_ERROR),
            TerminalDevice->DevicePath
            );
        }
        break;
      }

      RawFiFoInsertOneKey (TerminalDevice, Input);
    }
  }

  //
  // Translate all the raw data in RawFIFO into EFI Key,
  // according to different terminal type supported.
  //
  TranslateRawDataToEfiKey (TerminalDevice);
}
コード例 #4
0
ファイル: WinNtSerialIo.c プロジェクト: EvanLloyd/tianocore
EFI_STATUS
EFIAPI
WinNtSerialIoDriverBindingStart (
  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
  IN  EFI_HANDLE                    Handle,
  IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath
  )
/*++

Routine Description:

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Handle - add argument and description to function comment
// TODO:    RemainingDevicePath - add argument and description to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  EFI_STATUS                          Status;
  EFI_WIN_NT_IO_PROTOCOL              *WinNtIo;
  WIN_NT_SERIAL_IO_PRIVATE_DATA       *Private;
  HANDLE                              NtHandle;
  UART_DEVICE_PATH                    UartNode;
  EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
  UINTN                               EntryCount;
  UINTN                               Index;
  EFI_SERIAL_IO_PROTOCOL              *SerialIo;
  UART_DEVICE_PATH                    *Uart;
  UINT32                              FlowControlMap;
  UART_FLOW_CONTROL_DEVICE_PATH       *FlowControl;
  EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;
  UINT32                              Control;

  Private   = NULL;
  NtHandle  = INVALID_HANDLE_VALUE;

  //
  // Get the Parent Device Path
  //
  Status = gBS->OpenProtocol (
                  Handle,
                  &gEfiDevicePathProtocolGuid,
                  (VOID **) &ParentDevicePath,
                  This->DriverBindingHandle,
                  Handle,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    return Status;
  }

  //
  // Grab the IO abstraction we need to get any work done
  //
  Status = gBS->OpenProtocol (
                  Handle,
                  &gEfiWinNtIoProtocolGuid,
                  (VOID **) &WinNtIo,
                  This->DriverBindingHandle,
                  Handle,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    gBS->CloseProtocol (
          Handle,
          &gEfiDevicePathProtocolGuid,
          This->DriverBindingHandle,
          Handle
          );
    return Status;
  }

  if (Status == EFI_ALREADY_STARTED) {

    if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
      //
      // If RemainingDevicePath is NULL or is the End of Device Path Node
      //
      return EFI_SUCCESS;
    }

    //
    // Make sure a child handle does not already exist.  This driver can only
    // produce one child per serial port.
    //
    Status = gBS->OpenProtocolInformation (
                    Handle,
                    &gEfiWinNtIoProtocolGuid,
                    &OpenInfoBuffer,
                    &EntryCount
                    );
    if (EFI_ERROR (Status)) {
      return Status;
    }

    Status = EFI_ALREADY_STARTED;
    for (Index = 0; Index < EntryCount; Index++) {
      if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
        Status = gBS->OpenProtocol (
                        OpenInfoBuffer[Index].ControllerHandle,
                        &gEfiSerialIoProtocolGuid,
                        (VOID **) &SerialIo,
                        This->DriverBindingHandle,
                        Handle,
                        EFI_OPEN_PROTOCOL_GET_PROTOCOL
                        );
        if (!EFI_ERROR (Status)) {
          Uart   = (UART_DEVICE_PATH *) RemainingDevicePath;
          Status = SerialIo->SetAttributes (
                               SerialIo,
                               Uart->BaudRate,
                               SerialIo->Mode->ReceiveFifoDepth,
                               SerialIo->Mode->Timeout,
                               (EFI_PARITY_TYPE) Uart->Parity,
                               Uart->DataBits,
                               (EFI_STOP_BITS_TYPE) Uart->StopBits
                               );
          FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
          if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)) {
            Status = SerialIo->GetControl (SerialIo, &Control);
            if (!EFI_ERROR (Status)) {
              if (FlowControl->FlowControlMap == UART_FLOW_CONTROL_HARDWARE) {
                Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
              } else {
                Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
              }
              //
              // Clear the bits that are not allowed to pass to SetControl
              //
              Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
                          EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | 
                          EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
              Status = SerialIo->SetControl (SerialIo, Control);
            }
          }
        }
        break;
      }
    }

    FreePool (OpenInfoBuffer);
    return Status;
  }

  FlowControl    = NULL;
  FlowControlMap = 0;
  if (RemainingDevicePath == NULL) {
    //
    // Build the device path by appending the UART node to the ParentDevicePath
    // from the WinNtIo handle. The Uart setings are zero here, since
    // SetAttribute() will update them to match the default setings.
    //
    ZeroMem (&UartNode, sizeof (UART_DEVICE_PATH));
    UartNode.Header.Type     = MESSAGING_DEVICE_PATH;
    UartNode.Header.SubType  = MSG_UART_DP;
    SetDevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) &UartNode, sizeof (UART_DEVICE_PATH));

  } else if (!IsDevicePathEnd (RemainingDevicePath)) {
    //
    // If RemainingDevicePath isn't the End of Device Path Node, 
    // only scan the specified device by RemainingDevicePath
    //
    //
    // Match the configuration of the RemainingDevicePath. IsHandleSupported()
    // already checked to make sure the RemainingDevicePath contains settings
    // that we can support.
    //
    CopyMem (&UartNode, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
    FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
    if (IsUartFlowControlNode (FlowControl)) {
      FlowControlMap = FlowControl->FlowControlMap;
    } else {
      FlowControl    = NULL;
    }

  } else {
    //
    // If RemainingDevicePath is the End of Device Path Node,
    // skip enumerate any device and return EFI_SUCESSS
    // 
    return EFI_SUCCESS;
  }

  //
  // Check to see if we can access the hardware device. If it's Open in NT we
  // will not get access.
  //
  NtHandle = WinNtIo->WinNtThunk->CreateFile (
                                    WinNtIo->EnvString,
                                    GENERIC_READ | GENERIC_WRITE,
                                    0,
                                    NULL,
                                    OPEN_EXISTING,
                                    0,
                                    NULL
                                    );
  if (NtHandle == INVALID_HANDLE_VALUE) {
    Status = EFI_DEVICE_ERROR;
    goto Error;
  }

  //
  // Construct Private data
  //
  Private = AllocatePool (sizeof (WIN_NT_SERIAL_IO_PRIVATE_DATA));
  if (Private == NULL) {
    goto Error;
  }

  //
  // This signature must be valid before any member function is called
  //
  Private->Signature              = WIN_NT_SERIAL_IO_PRIVATE_DATA_SIGNATURE;
  Private->NtHandle               = NtHandle;
  Private->ControllerHandle       = Handle;
  Private->Handle                 = NULL;
  Private->WinNtThunk             = WinNtIo->WinNtThunk;
  Private->ParentDevicePath       = ParentDevicePath;
  Private->ControllerNameTable    = NULL;

  Private->SoftwareLoopbackEnable = FALSE;
  Private->HardwareLoopbackEnable = FALSE;
  Private->HardwareFlowControl    = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);
  Private->Fifo.First             = 0;
  Private->Fifo.Last              = 0;
  Private->Fifo.Surplus           = SERIAL_MAX_BUFFER_SIZE;

  CopyMem (&Private->UartDevicePath, &UartNode, sizeof (UART_DEVICE_PATH));

  AddUnicodeString2 (
    "eng",
    gWinNtSerialIoComponentName.SupportedLanguages,
    &Private->ControllerNameTable,
    WinNtIo->EnvString,
    TRUE
    );
  AddUnicodeString2 (
    "en",
    gWinNtSerialIoComponentName2.SupportedLanguages,
    &Private->ControllerNameTable,
    WinNtIo->EnvString,
    FALSE
    );


  Private->SerialIo.Revision      = SERIAL_IO_INTERFACE_REVISION;
  Private->SerialIo.Reset         = WinNtSerialIoReset;
  Private->SerialIo.SetAttributes = WinNtSerialIoSetAttributes;
  Private->SerialIo.SetControl    = WinNtSerialIoSetControl;
  Private->SerialIo.GetControl    = WinNtSerialIoGetControl;
  Private->SerialIo.Write         = WinNtSerialIoWrite;
  Private->SerialIo.Read          = WinNtSerialIoRead;
  Private->SerialIo.Mode          = &Private->SerialIoMode;

  //
  // Build the device path by appending the UART node to the ParentDevicePath
  // from the WinNtIo handle. The Uart setings are zero here, since
  // SetAttribute() will update them to match the current setings.
  //
  Private->DevicePath = AppendDevicePathNode (
                          ParentDevicePath,
                          (EFI_DEVICE_PATH_PROTOCOL *) &Private->UartDevicePath
                          );
  //
  // Only produce the FlowControl node when remaining device path has it
  //
  if (FlowControl != NULL) {
    TempDevicePath = Private->DevicePath;
    if (TempDevicePath != NULL) {
      Private->DevicePath = AppendDevicePathNode (
                              TempDevicePath,
                              (EFI_DEVICE_PATH_PROTOCOL *) FlowControl
                              );
      FreePool (TempDevicePath);
    }
  }
  if (Private->DevicePath == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Error;
  }

  //
  // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
  //
  Private->SerialIoMode.ControlMask       = SERIAL_CONTROL_MASK;
  Private->SerialIoMode.Timeout           = SERIAL_TIMEOUT_DEFAULT;
  Private->SerialIoMode.BaudRate          = Private->UartDevicePath.BaudRate;
  Private->SerialIoMode.ReceiveFifoDepth  = SERIAL_FIFO_DEFAULT;
  Private->SerialIoMode.DataBits          = Private->UartDevicePath.DataBits;
  Private->SerialIoMode.Parity            = Private->UartDevicePath.Parity;
  Private->SerialIoMode.StopBits          = Private->UartDevicePath.StopBits;

  //
  // Issue a reset to initialize the COM port
  //
  Status = Private->SerialIo.Reset (&Private->SerialIo);
  if (EFI_ERROR (Status)) {
    goto Error;
  }

  //
  // Create new child handle
  //
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &Private->Handle,
                  &gEfiSerialIoProtocolGuid,
                  &Private->SerialIo,
                  &gEfiDevicePathProtocolGuid,
                  Private->DevicePath,
                  NULL
                  );
  if (EFI_ERROR (Status)) {
    goto Error;
  }

  //
  // Open For Child Device
  //
  Status = gBS->OpenProtocol (
                  Handle,
                  &gEfiWinNtIoProtocolGuid,
                  (VOID **) &WinNtIo,
                  This->DriverBindingHandle,
                  Private->Handle,
                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
                  );
  if (EFI_ERROR (Status)) {
    goto Error;
  }

  return EFI_SUCCESS;

Error:
  //
  // Use the Stop() function to free all resources allocated in Start()
  //
  if (Private != NULL) {
    if (Private->Handle != NULL) {
      This->Stop (This, Handle, 1, &Private->Handle);
    } else {
      if (NtHandle != INVALID_HANDLE_VALUE) {
        Private->WinNtThunk->CloseHandle (NtHandle);
      }

      if (Private->DevicePath != NULL) {
        FreePool (Private->DevicePath);
      }

      FreeUnicodeStringTable (Private->ControllerNameTable);

      FreePool (Private);
    }
  }

  This->Stop (This, Handle, 0, NULL);

  return Status;
}