The Host Controller reset has been done at EDKII UHCI/EHCI/XHCI, The original code will do twice host controller initialization which is unnecessary. It also bring issues on some USB HCs. Cc: Star Zeng <star.zeng@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Feng Tian <feng.tian@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			1530 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1530 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
    Usb Bus Driver Binding and Bus IO Protocol.
 | 
						|
 | 
						|
Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "UsbBus.h"
 | 
						|
 | 
						|
EFI_USB_IO_PROTOCOL mUsbIoProtocol = {
 | 
						|
  UsbIoControlTransfer,
 | 
						|
  UsbIoBulkTransfer,
 | 
						|
  UsbIoAsyncInterruptTransfer,
 | 
						|
  UsbIoSyncInterruptTransfer,
 | 
						|
  UsbIoIsochronousTransfer,
 | 
						|
  UsbIoAsyncIsochronousTransfer,
 | 
						|
  UsbIoGetDeviceDescriptor,
 | 
						|
  UsbIoGetActiveConfigDescriptor,
 | 
						|
  UsbIoGetInterfaceDescriptor,
 | 
						|
  UsbIoGetEndpointDescriptor,
 | 
						|
  UsbIoGetStringDescriptor,
 | 
						|
  UsbIoGetSupportedLanguages,
 | 
						|
  UsbIoPortReset
 | 
						|
};
 | 
						|
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding = {
 | 
						|
  UsbBusControllerDriverSupported,
 | 
						|
  UsbBusControllerDriverStart,
 | 
						|
  UsbBusControllerDriverStop,
 | 
						|
  0xa,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  USB_IO function to execute a control transfer. This
 | 
						|
  function will execute the USB transfer. If transfer
 | 
						|
  successes, it will sync the internal state of USB bus
 | 
						|
  with device state.
 | 
						|
 | 
						|
  @param  This                   The USB_IO instance
 | 
						|
  @param  Request                The control transfer request
 | 
						|
  @param  Direction              Direction for data stage
 | 
						|
  @param  Timeout                The time to wait before timeout
 | 
						|
  @param  Data                   The buffer holding the data
 | 
						|
  @param  DataLength             Then length of the data
 | 
						|
  @param  UsbStatus              USB result
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER  The parameters are invalid
 | 
						|
  @retval EFI_SUCCESS            The control transfer succeeded.
 | 
						|
  @retval Others                 Failed to execute the transfer
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoControlTransfer (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL     *This,
 | 
						|
  IN  EFI_USB_DEVICE_REQUEST  *Request,
 | 
						|
  IN  EFI_USB_DATA_DIRECTION  Direction,
 | 
						|
  IN  UINT32                  Timeout,
 | 
						|
  IN  OUT VOID                *Data,      OPTIONAL
 | 
						|
  IN  UINTN                   DataLength, OPTIONAL
 | 
						|
  OUT UINT32                  *UsbStatus
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_DEVICE              *Dev;
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  USB_ENDPOINT_DESC       *EpDesc;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  if (UsbStatus == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf  = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  Dev    = UsbIf->Device;
 | 
						|
 | 
						|
  Status = UsbHcControlTransfer (
 | 
						|
             Dev->Bus,
 | 
						|
             Dev->Address,
 | 
						|
             Dev->Speed,
 | 
						|
             Dev->MaxPacket0,
 | 
						|
             Request,
 | 
						|
             Direction,
 | 
						|
             Data,
 | 
						|
             &DataLength,
 | 
						|
             (UINTN) Timeout,
 | 
						|
             &Dev->Translator,
 | 
						|
             UsbStatus
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {
 | 
						|
    //
 | 
						|
    // Clear TT buffer when CTRL/BULK split transaction failes
 | 
						|
    // Clear the TRANSLATOR TT buffer, not parent's buffer
 | 
						|
    //
 | 
						|
    ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices);
 | 
						|
    if (Dev->Translator.TranslatorHubAddress != 0) {
 | 
						|
      UsbHubCtrlClearTTBuffer (
 | 
						|
        Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],
 | 
						|
        Dev->Translator.TranslatorPortNumber,
 | 
						|
        Dev->Address,
 | 
						|
        0,
 | 
						|
        USB_ENDPOINT_CONTROL
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Some control transfer will change the device's internal
 | 
						|
  // status, such as Set_Configuration and Set_Interface.
 | 
						|
  // We must synchronize the bus driver's status with that in
 | 
						|
  // device. We ignore the Set_Descriptor request because it's
 | 
						|
  // hardly used by any device, especially in pre-boot environment
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Reset the endpoint toggle when endpoint stall is cleared
 | 
						|
  //
 | 
						|
  if ((Request->Request     == USB_REQ_CLEAR_FEATURE) &&
 | 
						|
      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,
 | 
						|
                                                 USB_TARGET_ENDPOINT)) &&
 | 
						|
      (Request->Value       == USB_FEATURE_ENDPOINT_HALT)) {
 | 
						|
 | 
						|
    EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8) Request->Index);
 | 
						|
 | 
						|
    if (EpDesc != NULL) {
 | 
						|
      EpDesc->Toggle = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Select a new configuration. This is a dangerous action. Upper driver
 | 
						|
  // should stop use its current UsbIo after calling this driver. The old
 | 
						|
  // UsbIo will be uninstalled and new UsbIo be installed. We can't use
 | 
						|
  // ReinstallProtocol since interfaces in different configuration may be
 | 
						|
  // completely irrelevant.
 | 
						|
  //
 | 
						|
  if ((Request->Request == USB_REQ_SET_CONFIG) &&
 | 
						|
      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,
 | 
						|
                                                 USB_TARGET_DEVICE))) {
 | 
						|
    //
 | 
						|
    // Don't re-create the USB interfaces if configuration isn't changed.
 | 
						|
    //
 | 
						|
    if ((Dev->ActiveConfig != NULL) &&
 | 
						|
        (Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue)) {
 | 
						|
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
    DEBUG ((EFI_D_INFO, "UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));
 | 
						|
 | 
						|
    if (Dev->ActiveConfig != NULL) {
 | 
						|
      UsbRemoveConfig (Dev);
 | 
						|
    }
 | 
						|
 | 
						|
    if (Request->Value != 0) {
 | 
						|
      Status = UsbSelectConfig (Dev, (UINT8) Request->Value);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Exit now, Old USB_IO is invalid now
 | 
						|
    //
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // A new alternative setting is selected for the interface.
 | 
						|
  // No need to reinstall UsbIo in this case because only
 | 
						|
  // underlying communication endpoints are changed. Functionality
 | 
						|
  // should remains the same.
 | 
						|
  //
 | 
						|
  if ((Request->Request     == USB_REQ_SET_INTERFACE) &&
 | 
						|
      (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD,
 | 
						|
                                                 USB_TARGET_INTERFACE)) &&
 | 
						|
      (Request->Index       == UsbIf->IfSetting->Desc.InterfaceNumber)) {
 | 
						|
 | 
						|
    Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8) Request->Value);
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      ASSERT (UsbIf->IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING);
 | 
						|
      UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Execute a bulk transfer to the device endpoint.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
  @param  Endpoint               The device endpoint.
 | 
						|
  @param  Data                   The data to transfer.
 | 
						|
  @param  DataLength             The length of the data to transfer.
 | 
						|
  @param  Timeout                Time to wait before timeout.
 | 
						|
  @param  UsbStatus              The result of USB transfer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The bulk transfer is OK.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
 | 
						|
  @retval Others                 Failed to execute transfer, reason returned in
 | 
						|
                                 UsbStatus.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoBulkTransfer (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL *This,
 | 
						|
  IN  UINT8               Endpoint,
 | 
						|
  IN  OUT VOID            *Data,
 | 
						|
  IN  OUT UINTN           *DataLength,
 | 
						|
  IN  UINTN               Timeout,
 | 
						|
  OUT UINT32              *UsbStatus
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_DEVICE              *Dev;
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  USB_ENDPOINT_DESC       *EpDesc;
 | 
						|
  UINT8                   BufNum;
 | 
						|
  UINT8                   Toggle;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||
 | 
						|
      (UsbStatus == NULL)) {
 | 
						|
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf   = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  Dev     = UsbIf->Device;
 | 
						|
 | 
						|
  EpDesc  = UsbGetEndpointDesc (UsbIf, Endpoint);
 | 
						|
 | 
						|
  if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  BufNum  = 1;
 | 
						|
  Toggle  = EpDesc->Toggle;
 | 
						|
  Status  = UsbHcBulkTransfer (
 | 
						|
              Dev->Bus,
 | 
						|
              Dev->Address,
 | 
						|
              Endpoint,
 | 
						|
              Dev->Speed,
 | 
						|
              EpDesc->Desc.MaxPacketSize,
 | 
						|
              BufNum,
 | 
						|
              &Data,
 | 
						|
              DataLength,
 | 
						|
              &Toggle,
 | 
						|
              Timeout,
 | 
						|
              &Dev->Translator,
 | 
						|
              UsbStatus
 | 
						|
              );
 | 
						|
 | 
						|
  EpDesc->Toggle = Toggle;
 | 
						|
 | 
						|
  if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) {
 | 
						|
    //
 | 
						|
    // Clear TT buffer when CTRL/BULK split transaction failes.
 | 
						|
    // Clear the TRANSLATOR TT buffer, not parent's buffer
 | 
						|
    //
 | 
						|
    ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices);
 | 
						|
    if (Dev->Translator.TranslatorHubAddress != 0) {
 | 
						|
      UsbHubCtrlClearTTBuffer (
 | 
						|
        Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress],
 | 
						|
        Dev->Translator.TranslatorPortNumber,
 | 
						|
        Dev->Address,
 | 
						|
        0,
 | 
						|
        USB_ENDPOINT_BULK
 | 
						|
        );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Execute a synchronous interrupt transfer.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
  @param  Endpoint               The device endpoint.
 | 
						|
  @param  Data                   The data to transfer.
 | 
						|
  @param  DataLength             The length of the data to transfer.
 | 
						|
  @param  Timeout                Time to wait before timeout.
 | 
						|
  @param  UsbStatus              The result of USB transfer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The synchronous interrupt transfer is OK.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
 | 
						|
  @retval Others                 Failed to execute transfer, reason returned in
 | 
						|
                                 UsbStatus.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoSyncInterruptTransfer (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL *This,
 | 
						|
  IN  UINT8               Endpoint,
 | 
						|
  IN  OUT VOID            *Data,
 | 
						|
  IN  OUT UINTN           *DataLength,
 | 
						|
  IN  UINTN               Timeout,
 | 
						|
  OUT UINT32              *UsbStatus
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_DEVICE              *Dev;
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  USB_ENDPOINT_DESC       *EpDesc;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
  UINT8                   Toggle;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) ||
 | 
						|
      (UsbStatus == NULL)) {
 | 
						|
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf   = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  Dev     = UsbIf->Device;
 | 
						|
 | 
						|
  EpDesc  = UsbGetEndpointDesc (UsbIf, Endpoint);
 | 
						|
 | 
						|
  if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Toggle = EpDesc->Toggle;
 | 
						|
  Status = UsbHcSyncInterruptTransfer (
 | 
						|
             Dev->Bus,
 | 
						|
             Dev->Address,
 | 
						|
             Endpoint,
 | 
						|
             Dev->Speed,
 | 
						|
             EpDesc->Desc.MaxPacketSize,
 | 
						|
             Data,
 | 
						|
             DataLength,
 | 
						|
             &Toggle,
 | 
						|
             Timeout,
 | 
						|
             &Dev->Translator,
 | 
						|
             UsbStatus
 | 
						|
             );
 | 
						|
 | 
						|
  EpDesc->Toggle = Toggle;
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Queue a new asynchronous interrupt transfer, or remove the old
 | 
						|
  request if (IsNewTransfer == FALSE).
 | 
						|
 | 
						|
  @param  This                   The USB_IO instance.
 | 
						|
  @param  Endpoint               The device endpoint.
 | 
						|
  @param  IsNewTransfer          Whether this is a new request, if it's old, remove
 | 
						|
                                 the request.
 | 
						|
  @param  PollInterval           The interval to poll the transfer result, (in ms).
 | 
						|
  @param  DataLength             The length of perodic data transfer.
 | 
						|
  @param  Callback               The function to call periodicaly when transfer is
 | 
						|
                                 ready.
 | 
						|
  @param  Context                The context to the callback.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            New transfer is queued or old request is removed.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
 | 
						|
  @retval Others                 Failed to queue the new request or remove the old
 | 
						|
                                 request.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoAsyncInterruptTransfer (
 | 
						|
  IN EFI_USB_IO_PROTOCOL              *This,
 | 
						|
  IN UINT8                            Endpoint,
 | 
						|
  IN BOOLEAN                          IsNewTransfer,
 | 
						|
  IN UINTN                            PollInterval,       OPTIONAL
 | 
						|
  IN UINTN                            DataLength,         OPTIONAL
 | 
						|
  IN EFI_ASYNC_USB_TRANSFER_CALLBACK  Callback,           OPTIONAL
 | 
						|
  IN VOID                             *Context            OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_DEVICE              *Dev;
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  USB_ENDPOINT_DESC       *EpDesc;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
  UINT8                   Toggle;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR (Endpoint) > 15)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
  UsbIf   = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  Dev     = UsbIf->Device;
 | 
						|
 | 
						|
  EpDesc  = UsbGetEndpointDesc (UsbIf, Endpoint);
 | 
						|
 | 
						|
  if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Toggle  = EpDesc->Toggle;
 | 
						|
  Status  = UsbHcAsyncInterruptTransfer (
 | 
						|
              Dev->Bus,
 | 
						|
              Dev->Address,
 | 
						|
              Endpoint,
 | 
						|
              Dev->Speed,
 | 
						|
              EpDesc->Desc.MaxPacketSize,
 | 
						|
              IsNewTransfer,
 | 
						|
              &Toggle,
 | 
						|
              PollInterval,
 | 
						|
              DataLength,
 | 
						|
              &Dev->Translator,
 | 
						|
              Callback,
 | 
						|
              Context
 | 
						|
              );
 | 
						|
 | 
						|
  EpDesc->Toggle = Toggle;
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Execute a synchronous isochronous transfer.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
  @param  DeviceEndpoint         The device endpoint.
 | 
						|
  @param  Data                   The data to transfer.
 | 
						|
  @param  DataLength             The length of the data to transfer.
 | 
						|
  @param  UsbStatus              The result of USB transfer.
 | 
						|
 | 
						|
  @retval EFI_UNSUPPORTED        Currently isochronous transfer isn't supported.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoIsochronousTransfer (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL *This,
 | 
						|
  IN  UINT8               DeviceEndpoint,
 | 
						|
  IN  OUT VOID            *Data,
 | 
						|
  IN  UINTN               DataLength,
 | 
						|
  OUT UINT32              *Status
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Queue an asynchronous isochronous transfer.
 | 
						|
 | 
						|
  @param  This                   The USB_IO instance.
 | 
						|
  @param  DeviceEndpoint         The device endpoint.
 | 
						|
  @param  Data                   The data to transfer.
 | 
						|
  @param  DataLength             The length of perodic data transfer.
 | 
						|
  @param  IsochronousCallBack    The function to call periodicaly when transfer is
 | 
						|
                                 ready.
 | 
						|
  @param  Context                The context to the callback.
 | 
						|
 | 
						|
  @retval EFI_UNSUPPORTED        Currently isochronous transfer isn't supported.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoAsyncIsochronousTransfer (
 | 
						|
  IN EFI_USB_IO_PROTOCOL              *This,
 | 
						|
  IN UINT8                            DeviceEndpoint,
 | 
						|
  IN OUT VOID                         *Data,
 | 
						|
  IN UINTN                            DataLength,
 | 
						|
  IN EFI_ASYNC_USB_TRANSFER_CALLBACK  IsochronousCallBack,
 | 
						|
  IN VOID                             *Context              OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the device descriptor of the device.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
  @param  Descriptor             The variable to receive the device descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The device descriptor is returned.
 | 
						|
  @retval EFI_INVALID_PARAMETER  The parameter is invalid.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoGetDeviceDescriptor (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL       *This,
 | 
						|
  OUT EFI_USB_DEVICE_DESCRIPTOR *Descriptor
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_DEVICE              *Dev;
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
 | 
						|
  if (Descriptor == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf  = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  Dev    = UsbIf->Device;
 | 
						|
 | 
						|
  CopyMem (Descriptor, &Dev->DevDesc->Desc, sizeof (EFI_USB_DEVICE_DESCRIPTOR));
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Return the configuration descriptor of the current active configuration.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
  @param  Descriptor             The USB configuration descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The active configuration descriptor is returned.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Some parameter is invalid.
 | 
						|
  @retval EFI_NOT_FOUND          Currently no active configuration is selected.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoGetActiveConfigDescriptor (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL       *This,
 | 
						|
  OUT EFI_USB_CONFIG_DESCRIPTOR *Descriptor
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_DEVICE              *Dev;
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
 | 
						|
  if (Descriptor == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf  = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  Dev    = UsbIf->Device;
 | 
						|
 | 
						|
  if (Dev->ActiveConfig == NULL) {
 | 
						|
    Status = EFI_NOT_FOUND;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (Descriptor, &(Dev->ActiveConfig->Desc), sizeof (EFI_USB_CONFIG_DESCRIPTOR));
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the active interface setting descriptor for this USB IO instance.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
  @param  Descriptor             The variable to receive active interface setting.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The active interface setting is returned.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Some parameter is invalid.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoGetInterfaceDescriptor (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL           *This,
 | 
						|
  OUT EFI_USB_INTERFACE_DESCRIPTOR  *Descriptor
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
 | 
						|
  if (Descriptor == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf  = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  CopyMem (Descriptor, &(UsbIf->IfSetting->Desc), sizeof (EFI_USB_INTERFACE_DESCRIPTOR));
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the endpoint descriptor from this interface setting.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
  @param  Index                  The index (start from zero) of the endpoint to
 | 
						|
                                 retrieve.
 | 
						|
  @param  Descriptor             The variable to receive the descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The endpoint descriptor is returned.
 | 
						|
  @retval EFI_INVALID_PARAMETER  Some parameter is invalid.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoGetEndpointDescriptor (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL         *This,
 | 
						|
  IN  UINT8                       Index,
 | 
						|
  OUT EFI_USB_ENDPOINT_DESCRIPTOR *Descriptor
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf  = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
 | 
						|
  if ((Descriptor == NULL) || (Index > 15)) {
 | 
						|
    gBS->RestoreTPL (OldTpl);
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) {
 | 
						|
    gBS->RestoreTPL (OldTpl);
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    Descriptor,
 | 
						|
    &(UsbIf->IfSetting->Endpoints[Index]->Desc),
 | 
						|
    sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
 | 
						|
    );
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the supported language ID table from the device.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
  @param  LangIDTable            The table to return the language IDs.
 | 
						|
  @param  TableSize              The size, in bytes, of the table LangIDTable.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The language ID is return.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoGetSupportedLanguages (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL *This,
 | 
						|
  OUT UINT16              **LangIDTable,
 | 
						|
  OUT UINT16              *TableSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_DEVICE              *Dev;
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
 | 
						|
  OldTpl        = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf         = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  Dev           = UsbIf->Device;
 | 
						|
 | 
						|
  *LangIDTable  = Dev->LangId;
 | 
						|
  *TableSize    = (UINT16) (Dev->TotalLangId * sizeof (UINT16));
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve an indexed string in the language of LangID.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
  @param  LangID                 The language ID of the string to retrieve.
 | 
						|
  @param  StringIndex            The index of the string.
 | 
						|
  @param  String                 The variable to receive the string.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The string is returned.
 | 
						|
  @retval EFI_NOT_FOUND          No such string existed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoGetStringDescriptor (
 | 
						|
  IN  EFI_USB_IO_PROTOCOL   *This,
 | 
						|
  IN  UINT16                LangID,
 | 
						|
  IN  UINT8                 StringIndex,
 | 
						|
  OUT CHAR16                **String
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_DEVICE                *Dev;
 | 
						|
  USB_INTERFACE             *UsbIf;
 | 
						|
  EFI_USB_STRING_DESCRIPTOR *StrDesc;
 | 
						|
  EFI_TPL                   OldTpl;
 | 
						|
  UINT8                     *Buf;
 | 
						|
  UINT8                     Index;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  if ((StringIndex == 0) || (LangID == 0)) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf  = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  Dev    = UsbIf->Device;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether language ID is supported
 | 
						|
  //
 | 
						|
  Status = EFI_NOT_FOUND;
 | 
						|
 | 
						|
  for (Index = 0; Index < Dev->TotalLangId; Index++) {
 | 
						|
    ASSERT (Index < USB_MAX_LANG_ID);
 | 
						|
    if (Dev->LangId[Index] == LangID) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Index == Dev->TotalLangId) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve the string descriptor then allocate a buffer
 | 
						|
  // to hold the string itself.
 | 
						|
  //
 | 
						|
  StrDesc = UsbGetOneString (Dev, StringIndex, LangID);
 | 
						|
 | 
						|
  if (StrDesc == NULL) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StrDesc->Length <= 2) {
 | 
						|
    goto FREE_STR;
 | 
						|
  }
 | 
						|
 | 
						|
  Buf = AllocateZeroPool (StrDesc->Length);
 | 
						|
 | 
						|
  if (Buf == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto FREE_STR;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (Buf, StrDesc->String, StrDesc->Length - 2);
 | 
						|
  *String = (CHAR16 *) Buf;
 | 
						|
  Status  = EFI_SUCCESS;
 | 
						|
 | 
						|
FREE_STR:
 | 
						|
  gBS->FreePool (StrDesc);
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Reset the device, then if that succeeds, reconfigure the
 | 
						|
  device with its address and current active configuration.
 | 
						|
 | 
						|
  @param  This                   The USB IO instance.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The device is reset and configured.
 | 
						|
  @retval Others                 Failed to reset the device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbIoPortReset (
 | 
						|
  IN EFI_USB_IO_PROTOCOL  *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_INTERFACE           *UsbIf;
 | 
						|
  USB_INTERFACE           *HubIf;
 | 
						|
  USB_DEVICE              *Dev;
 | 
						|
  EFI_TPL                 OldTpl;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINT8                   DevAddress;
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (USB_BUS_TPL);
 | 
						|
 | 
						|
  UsbIf  = USB_INTERFACE_FROM_USBIO (This);
 | 
						|
  Dev    = UsbIf->Device;
 | 
						|
 | 
						|
  if (UsbIf->IsHub) {
 | 
						|
    Status = EFI_INVALID_PARAMETER;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  HubIf  = Dev->ParentIf;
 | 
						|
  Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to reset hub port %d@hub  %d, %r \n",
 | 
						|
                Dev->ParentPort, Dev->ParentAddr, Status));
 | 
						|
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  HubIf->HubApi->ClearPortChange (HubIf, Dev->ParentPort);
 | 
						|
 | 
						|
  //
 | 
						|
  // Reset the device to its current address. The device now has an address
 | 
						|
  // of ZERO after port reset, so need to set Dev->Address to the device again for
 | 
						|
  // host to communicate with it.
 | 
						|
  //
 | 
						|
  DevAddress   = Dev->Address;
 | 
						|
  Dev->Address = 0;
 | 
						|
  Status  = UsbSetAddress (Dev, DevAddress);
 | 
						|
  Dev->Address = DevAddress;
 | 
						|
 | 
						|
  gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL);
 | 
						|
  
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // It may fail due to device disconnection or other reasons.
 | 
						|
    //
 | 
						|
    DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set address for device %d - %r\n",
 | 
						|
                Dev->Address, Status));
 | 
						|
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG (( EFI_D_INFO, "UsbIoPortReset: device is now ADDRESSED at %d\n", Dev->Address));
 | 
						|
 | 
						|
  //
 | 
						|
  // Reset the current active configure, after this device
 | 
						|
  // is in CONFIGURED state.
 | 
						|
  //
 | 
						|
  if (Dev->ActiveConfig != NULL) {
 | 
						|
    Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set configure for device %d - %r\n",
 | 
						|
                  Dev->Address, Status));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Install Usb Bus Protocol on host controller, and start the Usb bus.
 | 
						|
 | 
						|
  @param This                    The USB bus driver binding instance.
 | 
						|
  @param Controller              The controller to check.
 | 
						|
  @param RemainingDevicePath     The remaining device patch.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The controller is controlled by the usb bus.
 | 
						|
  @retval EFI_ALREADY_STARTED    The controller is already controlled by the usb bus.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusBuildProtocol (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_BUS                 *UsbBus;
 | 
						|
  USB_DEVICE              *RootHub;
 | 
						|
  USB_INTERFACE           *RootIf;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  EFI_STATUS              Status2;
 | 
						|
 | 
						|
  UsbBus = AllocateZeroPool (sizeof (USB_BUS));
 | 
						|
 | 
						|
  if (UsbBus == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbBus->Signature  = USB_BUS_SIGNATURE;
 | 
						|
  UsbBus->HostHandle = Controller;
 | 
						|
  UsbBus->MaxDevices = USB_MAX_DEVICES;
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &UsbBus->DevicePath,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open device path %r\n", Status));
 | 
						|
 | 
						|
    FreePool (UsbBus);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).
 | 
						|
  // This is for backward compatibility with EFI 1.x. In UEFI
 | 
						|
  // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2
 | 
						|
  // and USB_HC because EHCI driver will install both protocols
 | 
						|
  // (for the same reason). If we don't consume both of them,
 | 
						|
  // the unconsumed one may be opened by others.
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiUsb2HcProtocolGuid,
 | 
						|
                  (VOID **) &(UsbBus->Usb2Hc),
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
 | 
						|
  Status2 = gBS->OpenProtocol (
 | 
						|
                   Controller,
 | 
						|
                   &gEfiUsbHcProtocolGuid,
 | 
						|
                   (VOID **) &(UsbBus->UsbHc),
 | 
						|
                   This->DriverBindingHandle,
 | 
						|
                   Controller,
 | 
						|
                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                   );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));
 | 
						|
 | 
						|
    Status = EFI_DEVICE_ERROR;
 | 
						|
    goto CLOSE_HC;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // The EFI_USB2_HC_PROTOCOL is produced for XHCI support.
 | 
						|
    // Then its max supported devices are 256. Otherwise it's 128.
 | 
						|
    //
 | 
						|
    ASSERT (UsbBus->Usb2Hc != NULL);
 | 
						|
    if (UsbBus->Usb2Hc->MajorRevision == 0x3) {
 | 
						|
      UsbBus->MaxDevices = 256;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Install an EFI_USB_BUS_PROTOCOL to host controller to identify it.
 | 
						|
  //
 | 
						|
  Status = gBS->InstallProtocolInterface (
 | 
						|
                  &Controller,
 | 
						|
                  &gEfiCallerIdGuid,
 | 
						|
                  EFI_NATIVE_INTERFACE,
 | 
						|
                  &UsbBus->BusId
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status));
 | 
						|
    goto CLOSE_HC;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initial the wanted child device path list, and add first RemainingDevicePath
 | 
						|
  //
 | 
						|
  InitializeListHead (&UsbBus->WantedUsbIoDPList);
 | 
						|
  Status = UsbBusAddWantedUsbIoDP (&UsbBus->BusId, RemainingDevicePath);
 | 
						|
  ASSERT (!EFI_ERROR (Status));
 | 
						|
  //
 | 
						|
  // Create a fake usb device for root hub
 | 
						|
  //
 | 
						|
  RootHub = AllocateZeroPool (sizeof (USB_DEVICE));
 | 
						|
 | 
						|
  if (RootHub == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto UNINSTALL_USBBUS;
 | 
						|
  }
 | 
						|
 | 
						|
  RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));
 | 
						|
 | 
						|
  if (RootIf == NULL) {
 | 
						|
    FreePool (RootHub);
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto FREE_ROOTHUB;
 | 
						|
  }
 | 
						|
 | 
						|
  RootHub->Bus            = UsbBus;
 | 
						|
  RootHub->NumOfInterface = 1;
 | 
						|
  RootHub->Interfaces[0]  = RootIf;
 | 
						|
  RootHub->Tier           = 0;
 | 
						|
  RootIf->Signature       = USB_INTERFACE_SIGNATURE;
 | 
						|
  RootIf->Device          = RootHub;
 | 
						|
  RootIf->DevicePath      = UsbBus->DevicePath;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Report Status Code here since we will enumerate the USB devices
 | 
						|
  //
 | 
						|
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
    EFI_PROGRESS_CODE,
 | 
						|
    (EFI_IO_BUS_USB | EFI_IOB_PC_DETECT),
 | 
						|
    UsbBus->DevicePath
 | 
						|
    );
 | 
						|
  
 | 
						|
  Status                  = mUsbRootHubApi.Init (RootIf);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status));
 | 
						|
    goto FREE_ROOTHUB;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbBus->Devices[0] = RootHub;
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "UsbBusStart: usb bus started on %p, root hub %p\n", Controller, RootIf));
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
FREE_ROOTHUB:
 | 
						|
  if (RootIf != NULL) {
 | 
						|
    FreePool (RootIf);
 | 
						|
  }
 | 
						|
  if (RootHub != NULL) {
 | 
						|
    FreePool (RootHub);
 | 
						|
  }
 | 
						|
 | 
						|
UNINSTALL_USBBUS:
 | 
						|
  gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &UsbBus->BusId);
 | 
						|
 | 
						|
CLOSE_HC:
 | 
						|
  if (UsbBus->Usb2Hc != NULL) {
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          Controller,
 | 
						|
          &gEfiUsb2HcProtocolGuid,
 | 
						|
          This->DriverBindingHandle,
 | 
						|
          Controller
 | 
						|
          );
 | 
						|
  }
 | 
						|
  if (UsbBus->UsbHc != NULL) {
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          Controller,
 | 
						|
          &gEfiUsbHcProtocolGuid,
 | 
						|
          This->DriverBindingHandle,
 | 
						|
          Controller
 | 
						|
          );
 | 
						|
  }
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         Controller,
 | 
						|
         &gEfiDevicePathProtocolGuid,
 | 
						|
         This->DriverBindingHandle,
 | 
						|
         Controller
 | 
						|
         );
 | 
						|
  FreePool (UsbBus);
 | 
						|
 | 
						|
  DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status));
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  The USB bus driver entry pointer.
 | 
						|
 | 
						|
  @param ImageHandle       The driver image handle.
 | 
						|
  @param SystemTable       The system table.
 | 
						|
 | 
						|
  @return EFI_SUCCESS      The component name protocol is installed.
 | 
						|
  @return Others           Failed to init the usb driver.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusDriverEntryPoint (
 | 
						|
  IN EFI_HANDLE           ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE     *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EfiLibInstallDriverBindingComponentName2 (
 | 
						|
           ImageHandle,
 | 
						|
           SystemTable,
 | 
						|
           &mUsbBusDriverBinding,
 | 
						|
           ImageHandle,
 | 
						|
           &mUsbBusComponentName,
 | 
						|
           &mUsbBusComponentName2
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether USB bus driver support this device.
 | 
						|
 | 
						|
  @param  This                   The USB bus driver binding protocol.
 | 
						|
  @param  Controller             The controller handle to check.
 | 
						|
  @param  RemainingDevicePath    The remaining device path.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The bus supports this controller.
 | 
						|
  @retval EFI_UNSUPPORTED        This device isn't supported.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusControllerDriverSupported (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_DEV_PATH_PTR          DevicePathNode;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
 | 
						|
  EFI_USB2_HC_PROTOCOL      *Usb2Hc;
 | 
						|
  EFI_USB_HC_PROTOCOL       *UsbHc;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether device path is valid
 | 
						|
  //
 | 
						|
  if (RemainingDevicePath != NULL) {
 | 
						|
    //
 | 
						|
    // Check if RemainingDevicePath is the End of Device Path Node, 
 | 
						|
    // if yes, go on checking other conditions
 | 
						|
    //
 | 
						|
    if (!IsDevicePathEnd (RemainingDevicePath)) {
 | 
						|
      //
 | 
						|
      // If RemainingDevicePath isn't the End of Device Path Node,
 | 
						|
      // check its validation
 | 
						|
      //
 | 
						|
      DevicePathNode.DevPath = RemainingDevicePath;
 | 
						|
      
 | 
						|
      if ((DevicePathNode.DevPath->Type    != MESSAGING_DEVICE_PATH) ||
 | 
						|
          (DevicePathNode.DevPath->SubType != MSG_USB_DP &&
 | 
						|
           DevicePathNode.DevPath->SubType != MSG_USB_CLASS_DP
 | 
						|
           && DevicePathNode.DevPath->SubType != MSG_USB_WWID_DP
 | 
						|
           )) {
 | 
						|
      
 | 
						|
        return EFI_UNSUPPORTED;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether USB_HC2 protocol is installed
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiUsb2HcProtocolGuid,
 | 
						|
                  (VOID **) &Usb2Hc,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (Status == EFI_ALREADY_STARTED) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // If failed to open USB_HC2, fall back to USB_HC
 | 
						|
    //
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    Controller,
 | 
						|
                    &gEfiUsbHcProtocolGuid,
 | 
						|
                    (VOID **) &UsbHc,
 | 
						|
                    This->DriverBindingHandle,
 | 
						|
                    Controller,
 | 
						|
                    EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                    );
 | 
						|
    if (Status == EFI_ALREADY_STARTED) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Close the USB_HC used to perform the supported test
 | 
						|
    //
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          Controller,
 | 
						|
          &gEfiUsbHcProtocolGuid,
 | 
						|
          This->DriverBindingHandle,
 | 
						|
          Controller
 | 
						|
          );
 | 
						|
 | 
						|
  } else {
 | 
						|
 | 
						|
    //
 | 
						|
    // Close the USB_HC2 used to perform the supported test
 | 
						|
    //
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           Controller,
 | 
						|
           &gEfiUsb2HcProtocolGuid,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           Controller
 | 
						|
           );
 | 
						|
  }
 | 
						|
 
 | 
						|
  //
 | 
						|
  // Open the EFI Device Path protocol needed to perform the supported test
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &ParentDevicePath,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (Status == EFI_ALREADY_STARTED) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Close protocol, don't use device path protocol in the Support() function
 | 
						|
    //
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          Controller,
 | 
						|
          &gEfiDevicePathProtocolGuid,
 | 
						|
          This->DriverBindingHandle,
 | 
						|
          Controller
 | 
						|
          );
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Start to process the controller.
 | 
						|
 | 
						|
  @param  This                   The USB bus driver binding instance.
 | 
						|
  @param  Controller             The controller to check.
 | 
						|
  @param  RemainingDevicePath    The remaining device patch.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The controller is controlled by the usb bus.
 | 
						|
  @retval EFI_ALREADY_STARTED    The controller is already controlled by the usb
 | 
						|
                                 bus.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusControllerDriverStart (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_USB_BUS_PROTOCOL          *UsbBusId;
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL      *ParentDevicePath;
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &ParentDevicePath,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // Report Status Code here since we will initialize the host controller
 | 
						|
  //
 | 
						|
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
    EFI_PROGRESS_CODE,
 | 
						|
    (EFI_IO_BUS_USB | EFI_IOB_PC_INIT),
 | 
						|
    ParentDevicePath
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Locate the USB bus protocol, if it is found, USB bus
 | 
						|
  // is already started on this controller.
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiCallerIdGuid,
 | 
						|
                  (VOID **) &UsbBusId,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // If first start, build the bus execute environment and install bus protocol
 | 
						|
    //
 | 
						|
    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_IO_BUS_USB | EFI_P_PC_ENABLE));
 | 
						|
    Status = UsbBusBuildProtocol (This, Controller, RemainingDevicePath);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Try get the Usb Bus protocol interface again
 | 
						|
    //
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    Controller,
 | 
						|
                    &gEfiCallerIdGuid,
 | 
						|
                    (VOID **) &UsbBusId,
 | 
						|
                    This->DriverBindingHandle,
 | 
						|
                    Controller,
 | 
						|
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                    );
 | 
						|
    ASSERT (!EFI_ERROR (Status));
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // USB Bus driver need to control the recursive connect policy of the bus, only those wanted
 | 
						|
    // usb child device will be recursively connected.
 | 
						|
    // The RemainingDevicePath indicate the child usb device which user want to fully recursively connecte this time.
 | 
						|
    // All wanted usb child devices will be remembered by the usb bus driver itself.
 | 
						|
    // If RemainingDevicePath == NULL, all the usb child devices in the usb bus are wanted devices.
 | 
						|
    //
 | 
						|
    // Save the passed in RemainingDevicePath this time
 | 
						|
    //
 | 
						|
    if (RemainingDevicePath != NULL) {
 | 
						|
      if (IsDevicePathEnd (RemainingDevicePath)) {
 | 
						|
        //
 | 
						|
        // If RemainingDevicePath is the End of Device Path Node,
 | 
						|
        // skip enumerate any device and return EFI_SUCESSS
 | 
						|
        // 
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    Status = UsbBusAddWantedUsbIoDP (UsbBusId, RemainingDevicePath);
 | 
						|
    ASSERT (!EFI_ERROR (Status));
 | 
						|
    //
 | 
						|
    // Ensure all wanted child usb devices are fully recursively connected
 | 
						|
    //
 | 
						|
    Status = UsbBusRecursivelyConnectWantedUsbIo (UsbBusId);
 | 
						|
    ASSERT (!EFI_ERROR (Status));
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Stop handle the controller by this USB bus driver.
 | 
						|
 | 
						|
  @param  This                   The USB bus driver binding protocol.
 | 
						|
  @param  Controller             The controller to release.
 | 
						|
  @param  NumberOfChildren       The child of USB bus that opened controller
 | 
						|
                                 BY_CHILD.
 | 
						|
  @param  ChildHandleBuffer      The array of child handle.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The controller or children are stopped.
 | 
						|
  @retval EFI_DEVICE_ERROR       Failed to stop the driver.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusControllerDriverStop (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   Controller,
 | 
						|
  IN UINTN                        NumberOfChildren,
 | 
						|
  IN EFI_HANDLE                   *ChildHandleBuffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  USB_BUS               *Bus;
 | 
						|
  USB_DEVICE            *RootHub;
 | 
						|
  USB_DEVICE            *UsbDev;
 | 
						|
  USB_INTERFACE         *RootIf;
 | 
						|
  USB_INTERFACE         *UsbIf;
 | 
						|
  EFI_USB_BUS_PROTOCOL  *BusId;
 | 
						|
  EFI_USB_IO_PROTOCOL   *UsbIo;
 | 
						|
  EFI_TPL               OldTpl;
 | 
						|
  UINTN                 Index;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  EFI_STATUS            ReturnStatus;
 | 
						|
 | 
						|
  Status  = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (NumberOfChildren > 0) {
 | 
						|
    //
 | 
						|
    // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict
 | 
						|
    //
 | 
						|
    OldTpl   = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
    ReturnStatus = EFI_SUCCESS;
 | 
						|
    for (Index = 0; Index < NumberOfChildren; Index++) {
 | 
						|
      Status = gBS->OpenProtocol (
 | 
						|
                      ChildHandleBuffer[Index],
 | 
						|
                      &gEfiUsbIoProtocolGuid,
 | 
						|
                      (VOID **) &UsbIo,
 | 
						|
                      This->DriverBindingHandle,
 | 
						|
                      Controller,
 | 
						|
                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                      );
 | 
						|
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // It is possible that the child has already been released:
 | 
						|
        // 1. For combo device, free one device will release others.
 | 
						|
        // 2. If a hub is released, all devices on its down facing
 | 
						|
        //    ports are released also.
 | 
						|
        //
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      UsbIf   = USB_INTERFACE_FROM_USBIO (UsbIo);
 | 
						|
      UsbDev  = UsbIf->Device;
 | 
						|
 | 
						|
      ReturnStatus = UsbRemoveDevice (UsbDev);
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->RestoreTPL (OldTpl);
 | 
						|
    return ReturnStatus;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG (( EFI_D_INFO, "UsbBusStop: usb bus stopped on %p\n", Controller));
 | 
						|
 | 
						|
  //
 | 
						|
  // Locate USB_BUS for the current host controller
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &gEfiCallerIdGuid,
 | 
						|
                  (VOID **) &BusId,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Bus = USB_BUS_FROM_THIS (BusId);
 | 
						|
 | 
						|
  //
 | 
						|
  // Stop the root hub, then free all the devices
 | 
						|
  //
 | 
						|
  // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict
 | 
						|
  //
 | 
						|
  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  RootHub = Bus->Devices[0];
 | 
						|
  RootIf  = RootHub->Interfaces[0];
 | 
						|
 | 
						|
  ASSERT (Bus->MaxDevices <= 256);
 | 
						|
  ReturnStatus = EFI_SUCCESS;
 | 
						|
  for (Index = 1; Index < Bus->MaxDevices; Index++) {
 | 
						|
    if (Bus->Devices[Index] != NULL) {
 | 
						|
      Status = UsbRemoveDevice (Bus->Devices[Index]);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        ReturnStatus = Status;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
 | 
						|
  if (!EFI_ERROR (ReturnStatus)) {
 | 
						|
    mUsbRootHubApi.Release (RootIf);
 | 
						|
    gBS->FreePool   (RootIf);
 | 
						|
    gBS->FreePool   (RootHub);
 | 
						|
 | 
						|
    Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);
 | 
						|
    ASSERT (!EFI_ERROR (Status));
 | 
						|
 | 
						|
    //
 | 
						|
    // Uninstall the bus identifier and close USB_HC/USB2_HC protocols
 | 
						|
    //
 | 
						|
    gBS->UninstallProtocolInterface (Controller, &gEfiCallerIdGuid, &Bus->BusId);
 | 
						|
 | 
						|
    if (Bus->Usb2Hc != NULL) {
 | 
						|
      Status = gBS->CloseProtocol (
 | 
						|
                      Controller,
 | 
						|
                      &gEfiUsb2HcProtocolGuid,
 | 
						|
                      This->DriverBindingHandle,
 | 
						|
                      Controller
 | 
						|
                      );
 | 
						|
    }
 | 
						|
 | 
						|
    if (Bus->UsbHc != NULL) {
 | 
						|
      Status = gBS->CloseProtocol (
 | 
						|
                      Controller,
 | 
						|
                      &gEfiUsbHcProtocolGuid,
 | 
						|
                      This->DriverBindingHandle,
 | 
						|
                      Controller
 | 
						|
                      );
 | 
						|
    }
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiDevicePathProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
 | 
						|
      gBS->FreePool (Bus);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 |