git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1037 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			3750 lines
		
	
	
		
			107 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3750 lines
		
	
	
		
			107 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++
 | 
						|
 | 
						|
Copyright (c) 2006, Intel Corporation                                                         
 | 
						|
All rights reserved. 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.             
 | 
						|
 | 
						|
  Module Name:
 | 
						|
 | 
						|
    UsbBus.c
 | 
						|
 | 
						|
  Abstract:
 | 
						|
 | 
						|
    USB Bus Driver
 | 
						|
 | 
						|
  Revision History
 | 
						|
 | 
						|
--*/
 | 
						|
 | 
						|
#include "usbbus.h"
 | 
						|
 | 
						|
UINTN                       gUSBDebugLevel  = EFI_D_INFO;
 | 
						|
UINTN                       gUSBErrorLevel  = EFI_D_ERROR;
 | 
						|
 | 
						|
//
 | 
						|
// The UsbBusProtocol is just used to locate USB_BUS_CONTROLLER
 | 
						|
// structure in the UsbBusDriverControllerDriverStop(). Then we can
 | 
						|
// Close all opened protocols and release this structure.
 | 
						|
//
 | 
						|
STATIC EFI_GUID             mUsbBusProtocolGuid = EFI_USB_BUS_PROTOCOL_GUID;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
//
 | 
						|
// EFI_DRIVER_BINDING_PROTOCOL Protocol Interface
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusControllerDriverSupported (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | 
						|
  IN EFI_HANDLE                      Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | 
						|
  );
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusControllerDriverStart (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | 
						|
  IN EFI_HANDLE                      Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | 
						|
  );
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusControllerDriverStop (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | 
						|
  IN EFI_HANDLE                      Controller,
 | 
						|
  IN UINTN                           NumberOfChildren,
 | 
						|
  IN EFI_HANDLE                      *ChildHandleBuffer
 | 
						|
  );
 | 
						|
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL gUsbBusDriverBinding = {
 | 
						|
  UsbBusControllerDriverSupported,
 | 
						|
  UsbBusControllerDriverStart,
 | 
						|
  UsbBusControllerDriverStop,
 | 
						|
  0x10,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// Internal use only
 | 
						|
//
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
ReportUsbStatusCode (
 | 
						|
  IN USB_BUS_CONTROLLER_DEVICE     *UsbBusController,
 | 
						|
  IN EFI_STATUS_CODE_TYPE          Type,
 | 
						|
  IN EFI_STATUS_CODE_VALUE         Code
 | 
						|
  );
 | 
						|
 | 
						|
//
 | 
						|
// Supported function
 | 
						|
//
 | 
						|
VOID
 | 
						|
InitializeUsbIoInstance (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE     *UsbIoController
 | 
						|
  );
 | 
						|
 | 
						|
STATIC
 | 
						|
USB_IO_CONTROLLER_DEVICE    *
 | 
						|
CreateUsbIoControllerDevice (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
InitUsbIoController (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE     *UsbIoController
 | 
						|
  );
 | 
						|
 | 
						|
//
 | 
						|
// USB Device Configuration / Deconfiguration
 | 
						|
//
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
UsbDeviceConfiguration (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE     *ParentHubController,
 | 
						|
  IN EFI_HANDLE                   HostController,
 | 
						|
  IN UINT8                        ParentPort,
 | 
						|
  IN USB_IO_DEVICE                *UsbIoDevice
 | 
						|
  );
 | 
						|
 | 
						|
//
 | 
						|
// Usb Bus enumeration function
 | 
						|
//
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
RootHubEnumeration (
 | 
						|
  IN EFI_EVENT     Event,
 | 
						|
  IN VOID          *Context
 | 
						|
  );
 | 
						|
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
HubEnumeration (
 | 
						|
  IN EFI_EVENT     Event,
 | 
						|
  IN VOID          *Context
 | 
						|
  );
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
UsbSetTransactionTranslator (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE     *ParentHubController,
 | 
						|
  IN UINT8                        ParentPort,
 | 
						|
  IN OUT USB_IO_DEVICE            *Device
 | 
						|
  );
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
UsbUnsetTransactionTranslator (
 | 
						|
  USB_IO_DEVICE *Device
 | 
						|
  );
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
IdentifyDeviceSpeed (
 | 
						|
  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  USB_IO_DEVICE             *NewDevice,
 | 
						|
  UINT8                     Index
 | 
						|
  );
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
ReleasePortToCHC (
 | 
						|
  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  UINT8                     PortNum
 | 
						|
  );
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
ResetRootPort (
 | 
						|
  IN USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  IN UINT8                     PortNum,
 | 
						|
  IN UINT8                     RetryTimes
 | 
						|
  );
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
ResetHubPort (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE    *UsbIoController,
 | 
						|
  IN UINT8                       PortIndex
 | 
						|
  );
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
ParentPortReset (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE    *UsbIoController,
 | 
						|
  IN BOOLEAN                     ReConfigure,
 | 
						|
  IN UINT8                       RetryTimes
 | 
						|
  );
 | 
						|
 | 
						|
//
 | 
						|
// Following are address allocate and free functions
 | 
						|
//
 | 
						|
STATIC
 | 
						|
UINT8
 | 
						|
UsbAllocateAddress (
 | 
						|
  IN UINT8    *AddressPool
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Allocate address for usb device
 | 
						|
 | 
						|
  Arguments:
 | 
						|
   AddressPool - Pool of usb device address
 | 
						|
 | 
						|
  Returns:
 | 
						|
   Usb device address
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8 ByteIndex;
 | 
						|
  UINT8 BitIndex;
 | 
						|
 | 
						|
  for (ByteIndex = 0; ByteIndex < 16; ByteIndex++) {
 | 
						|
    for (BitIndex = 0; BitIndex < 8; BitIndex++) {
 | 
						|
      if ((AddressPool[ByteIndex] & (1 << BitIndex)) == 0) {
 | 
						|
        //
 | 
						|
        // Found one, covert to address, and mark it use
 | 
						|
        //
 | 
						|
        AddressPool[ByteIndex] |= (1 << BitIndex);
 | 
						|
        return (UINT8) (ByteIndex * 8 + BitIndex);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
UsbFreeAddress (
 | 
						|
  IN UINT8     DevAddress,
 | 
						|
  IN UINT8     *AddressPool
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Free address for usb device
 | 
						|
 | 
						|
  Arguments:
 | 
						|
   DevAddress  - Usb device address
 | 
						|
   AddressPool - Pool of usb device address
 | 
						|
   
 | 
						|
  Returns:
 | 
						|
   VOID
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8 WhichByte;
 | 
						|
  UINT8 WhichBit;
 | 
						|
  //
 | 
						|
  // Locate the position
 | 
						|
  //
 | 
						|
  WhichByte = (UINT8) (DevAddress / 8);
 | 
						|
  WhichBit  = (UINT8) (DevAddress & 0x7);
 | 
						|
 | 
						|
  AddressPool[WhichByte] &= (~(1 << WhichBit));
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusControllerDriverSupported (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | 
						|
  IN EFI_HANDLE                      Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Test to see if this driver supports ControllerHandle. Any ControllerHandle
 | 
						|
    that has UsbHcProtocol installed will be supported.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    This                - Protocol instance pointer.
 | 
						|
    Controller          - Handle of device to test
 | 
						|
    RemainingDevicePath - Device Path Protocol instance pointer
 | 
						|
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS         - This driver supports this device.
 | 
						|
    EFI_UNSUPPORTED     - This driver does not support this device.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                 Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL   *ParentDevicePath;
 | 
						|
  EFI_USB2_HC_PROTOCOL       *Usb2Hc;
 | 
						|
  EFI_USB_HC_PROTOCOL        *UsbHc;
 | 
						|
  EFI_DEV_PATH_PTR           Node;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check Device Path
 | 
						|
  //
 | 
						|
  if (RemainingDevicePath != NULL) {
 | 
						|
    Node.DevPath = RemainingDevicePath;
 | 
						|
    if (Node.DevPath->Type != MESSAGING_DEVICE_PATH ||
 | 
						|
        Node.DevPath->SubType != MSG_USB_DP         ||
 | 
						|
        DevicePathNodeLength(Node.DevPath) != sizeof(USB_DEVICE_PATH)) {
 | 
						|
      return EFI_UNSUPPORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Open the IO Abstraction(s) 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)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         Controller,
 | 
						|
         &gEfiDevicePathProtocolGuid,
 | 
						|
         This->DriverBindingHandle,
 | 
						|
         Controller
 | 
						|
         );
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Check whether USB Host Controller Protocol is already
 | 
						|
  // installed on this handle. If it is installed, we can start
 | 
						|
  // USB Bus Driver now.
 | 
						|
  //
 | 
						|
  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)) {
 | 
						|
    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;
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->CloseProtocol (
 | 
						|
      Controller,
 | 
						|
      &gEfiUsbHcProtocolGuid,
 | 
						|
      This->DriverBindingHandle,
 | 
						|
      Controller
 | 
						|
      );
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  
 | 
						|
  gBS->CloseProtocol (
 | 
						|
    Controller,
 | 
						|
    &gEfiUsb2HcProtocolGuid,
 | 
						|
    This->DriverBindingHandle,
 | 
						|
    Controller
 | 
						|
    );
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusControllerDriverStart (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | 
						|
  IN EFI_HANDLE                      Controller,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
 | 
						|
    Starting the Usb Bus Driver
 | 
						|
 | 
						|
  Arguments:
 | 
						|
 | 
						|
    This                - Protocol instance pointer.
 | 
						|
    Controller          - Handle of device to test
 | 
						|
    RemainingDevicePath - Not used
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    EFI_SUCCESS         - This driver supports this device.
 | 
						|
    EFI_DEVICE_ERROR    - This driver cannot be started due to device
 | 
						|
    EFI_OUT_OF_RESOURCES- Can't allocate memory resources
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_STATUS                OpenStatus;
 | 
						|
  USB_BUS_CONTROLLER_DEVICE *UsbBusDev;
 | 
						|
  USB_IO_DEVICE             *RootHub;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *RootHubController;
 | 
						|
  UINT8                     MaxSpeed;
 | 
						|
  UINT8                     PortNumber;
 | 
						|
  UINT8                     Is64BitCapable;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate USB_BUS_CONTROLLER_DEVICE structure
 | 
						|
  //
 | 
						|
  UsbBusDev = NULL;
 | 
						|
  UsbBusDev = AllocateZeroPool (sizeof (USB_BUS_CONTROLLER_DEVICE));
 | 
						|
  if (UsbBusDev == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbBusDev->Signature      = USB_BUS_DEVICE_SIGNATURE;
 | 
						|
  UsbBusDev->AddressPool[0] = 1;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the Device Path Protocol on Controller's handle
 | 
						|
  //
 | 
						|
  OpenStatus = gBS->OpenProtocol (
 | 
						|
                      Controller,
 | 
						|
                      &gEfiDevicePathProtocolGuid,
 | 
						|
                      (VOID **) &UsbBusDev->DevicePath,
 | 
						|
                      This->DriverBindingHandle,
 | 
						|
                      Controller,
 | 
						|
                      EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                      );
 | 
						|
 | 
						|
  if (EFI_ERROR (OpenStatus)) {
 | 
						|
    gBS->FreePool (UsbBusDev);
 | 
						|
    return OpenStatus;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Locate the Host Controller Interface
 | 
						|
  //
 | 
						|
  OpenStatus = gBS->OpenProtocol (
 | 
						|
                      Controller,
 | 
						|
                      &gEfiUsb2HcProtocolGuid,
 | 
						|
                      (VOID **) &(UsbBusDev->Usb2HCInterface),
 | 
						|
                      This->DriverBindingHandle,
 | 
						|
                      Controller,
 | 
						|
                      EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                      );
 | 
						|
  if (EFI_ERROR (OpenStatus)) {
 | 
						|
 | 
						|
    UsbBusDev->Hc2ProtocolSupported = FALSE;
 | 
						|
    OpenStatus = gBS->OpenProtocol (
 | 
						|
                        Controller,
 | 
						|
                        &gEfiUsbHcProtocolGuid,
 | 
						|
                        (VOID **) &(UsbBusDev->UsbHCInterface),
 | 
						|
                        This->DriverBindingHandle,
 | 
						|
                        Controller,
 | 
						|
                        EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                        );
 | 
						|
    if (EFI_ERROR (OpenStatus)) {
 | 
						|
      //
 | 
						|
      // Report Status Code here since we will reset the host controller
 | 
						|
      //
 | 
						|
      REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
        EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | 
						|
        EFI_IO_BUS_USB | EFI_IOB_EC_CONTROLLER_ERROR,
 | 
						|
        UsbBusDev->DevicePath
 | 
						|
        );
 | 
						|
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiDevicePathProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
      gBS->FreePool (UsbBusDev);
 | 
						|
      return OpenStatus;
 | 
						|
    }
 | 
						|
 | 
						|
    DEBUG ((gUSBDebugLevel, "UsbHcProtocol Opened.\n"));
 | 
						|
  } else {
 | 
						|
    DEBUG ((gUSBDebugLevel, "Usb2HcProtocol Opened.\n"));
 | 
						|
    UsbBusDev->Hc2ProtocolSupported = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Attach EFI_USB_BUS_PROTOCOL to controller handle,
 | 
						|
  // for locate UsbBusDev later
 | 
						|
  //
 | 
						|
  Status = gBS->InstallProtocolInterface (
 | 
						|
                  &Controller,
 | 
						|
                  &mUsbBusProtocolGuid,
 | 
						|
                  EFI_NATIVE_INTERFACE,
 | 
						|
                  &UsbBusDev->BusIdentify
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           Controller,
 | 
						|
           &gEfiDevicePathProtocolGuid,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           Controller
 | 
						|
           );
 | 
						|
    if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsb2HcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    } else {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsbHcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->FreePool (UsbBusDev);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Add root hub to the tree
 | 
						|
  //
 | 
						|
  RootHub = NULL;
 | 
						|
  RootHub = AllocateZeroPool (sizeof (USB_IO_DEVICE));
 | 
						|
  if (RootHub == NULL) {
 | 
						|
    gBS->UninstallProtocolInterface (
 | 
						|
           Controller,
 | 
						|
           &mUsbBusProtocolGuid,
 | 
						|
           &UsbBusDev->BusIdentify
 | 
						|
           );
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           Controller,
 | 
						|
           &gEfiDevicePathProtocolGuid,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           Controller
 | 
						|
           );
 | 
						|
    if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsb2HcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    } else {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsbHcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->FreePool (UsbBusDev);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  RootHub->BusController  = UsbBusDev;
 | 
						|
  RootHub->DeviceAddress  = UsbAllocateAddress (UsbBusDev->AddressPool);
 | 
						|
 | 
						|
  UsbBusDev->Root         = RootHub;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate Root Hub Controller
 | 
						|
  //
 | 
						|
  RootHubController = CreateUsbIoControllerDevice ();
 | 
						|
  if (RootHubController == NULL) {
 | 
						|
    gBS->UninstallProtocolInterface (
 | 
						|
           Controller,
 | 
						|
           &mUsbBusProtocolGuid,
 | 
						|
           &UsbBusDev->BusIdentify
 | 
						|
           );
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           Controller,
 | 
						|
           &gEfiDevicePathProtocolGuid,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           Controller
 | 
						|
           );
 | 
						|
    if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsb2HcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    } else {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsbHcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    }
 | 
						|
    gBS->FreePool (UsbBusDev);
 | 
						|
    gBS->FreePool (RootHub);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbVirtualHcGetCapability (
 | 
						|
    UsbBusDev,
 | 
						|
    &MaxSpeed,
 | 
						|
    &PortNumber,
 | 
						|
    &Is64BitCapable
 | 
						|
    );
 | 
						|
  RootHubController->DownstreamPorts  = PortNumber;
 | 
						|
  RootHubController->UsbDevice        = RootHub;
 | 
						|
  RootHubController->IsUsbHub         = TRUE;
 | 
						|
  RootHubController->DevicePath       = UsbBusDev->DevicePath;
 | 
						|
  RootHubController->HostController   = Controller;
 | 
						|
 | 
						|
  RootHub->NumOfControllers           = 1;
 | 
						|
  RootHub->UsbController[0]           = RootHubController;
 | 
						|
  RootHub->DeviceSpeed                = MaxSpeed;
 | 
						|
 | 
						|
  //
 | 
						|
  // Report Status Code here since we will reset the host controller
 | 
						|
  //
 | 
						|
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
    EFI_PROGRESS_CODE,
 | 
						|
    EFI_IO_BUS_USB | EFI_IOB_PC_RESET,
 | 
						|
    UsbBusDev->DevicePath
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Reset USB Host Controller
 | 
						|
  //
 | 
						|
  UsbVirtualHcReset (
 | 
						|
    UsbBusDev,
 | 
						|
    EFI_USB_HC_RESET_GLOBAL
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Report Status Code while we are going to bring up the Host Controller
 | 
						|
  // and start bus enumeration
 | 
						|
  //
 | 
						|
  REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
    EFI_PROGRESS_CODE,
 | 
						|
    EFI_IO_BUS_USB | EFI_IOB_PC_ENABLE,
 | 
						|
    UsbBusDev->DevicePath
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Start USB Host Controller
 | 
						|
  //
 | 
						|
  UsbVirtualHcSetState (
 | 
						|
    UsbBusDev,
 | 
						|
    EfiUsbHcStateOperational
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Create a timer to query root ports periodically
 | 
						|
  //
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
 | 
						|
                  EFI_TPL_CALLBACK,
 | 
						|
                  RootHubEnumeration,
 | 
						|
                  RootHubController,
 | 
						|
                  &RootHubController->HubNotify
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->UninstallProtocolInterface (
 | 
						|
           Controller,
 | 
						|
           &mUsbBusProtocolGuid,
 | 
						|
           &UsbBusDev->BusIdentify
 | 
						|
           );
 | 
						|
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           Controller,
 | 
						|
           &gEfiDevicePathProtocolGuid,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           Controller
 | 
						|
           );
 | 
						|
 | 
						|
    if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsb2HcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    } else {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsbHcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->FreePool (RootHubController);
 | 
						|
    gBS->FreePool (RootHub);
 | 
						|
    gBS->FreePool (UsbBusDev);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Before depending on the timer to check root ports periodically,
 | 
						|
  // here we should check them immediately for the first time, or
 | 
						|
  // there will be an interval between bus start and devices start.
 | 
						|
  //
 | 
						|
  gBS->SignalEvent (RootHubController->HubNotify);
 | 
						|
  
 | 
						|
  Status = gBS->SetTimer (
 | 
						|
                  RootHubController->HubNotify,
 | 
						|
                  TimerPeriodic,
 | 
						|
                  BUSPOLLING_PERIOD
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->UninstallProtocolInterface (
 | 
						|
           Controller,
 | 
						|
           &mUsbBusProtocolGuid,
 | 
						|
           &UsbBusDev->BusIdentify
 | 
						|
           );
 | 
						|
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           Controller,
 | 
						|
           &gEfiDevicePathProtocolGuid,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           Controller
 | 
						|
           );
 | 
						|
 | 
						|
    if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsb2HcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    } else {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             Controller,
 | 
						|
             &gEfiUsbHcProtocolGuid,
 | 
						|
             This->DriverBindingHandle,
 | 
						|
             Controller
 | 
						|
             );
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->CloseEvent (RootHubController->HubNotify);
 | 
						|
    gBS->FreePool (RootHubController);
 | 
						|
    gBS->FreePool (RootHub);
 | 
						|
    gBS->FreePool (UsbBusDev);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Stop the bus controller
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbBusControllerDriverStop (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | 
						|
  IN EFI_HANDLE                      Controller,
 | 
						|
  IN UINTN                           NumberOfChildren,
 | 
						|
  IN EFI_HANDLE                      *ChildHandleBuffer
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Stop this driver on ControllerHandle. Support stoping any child handles
 | 
						|
    created by this driver.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    This              - Protocol instance pointer.
 | 
						|
    Controller        - Handle of device to stop driver on
 | 
						|
    NumberOfChildren  - Number of Children in the ChildHandleBuffer
 | 
						|
    ChildHandleBuffer - List of handles for the children we need to stop.
 | 
						|
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
    others
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  USB_IO_DEVICE             *Root;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *RootHubController;
 | 
						|
  USB_BUS_CONTROLLER_DEVICE *UsbBusController;
 | 
						|
  EFI_USB_BUS_PROTOCOL      *UsbIdentifier;
 | 
						|
  UINT8                     Index2;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *UsbController;
 | 
						|
  USB_IO_DEVICE             *UsbIoDevice;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *HubController;
 | 
						|
  UINTN                     Index;
 | 
						|
  EFI_USB_IO_PROTOCOL       *UsbIo;
 | 
						|
 | 
						|
  if (NumberOfChildren > 0) {
 | 
						|
 | 
						|
    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)) {
 | 
						|
        //
 | 
						|
        // We are here since the handle passed in does not support
 | 
						|
        // UsbIo protocol. There are several reasons that will cause
 | 
						|
        // this.
 | 
						|
        // For combo device such as keyboard, it may have 2 devices
 | 
						|
        // in one, namely, keyboard and mouse. If we deconfigure one
 | 
						|
        // of them, the other will be freed at the same time. This will
 | 
						|
        // cause the status error. But this is the correct behavior.
 | 
						|
        // For hub device, if we deconfigure hub first, the other chile
 | 
						|
        // device will be disconnected also, this will also provide us
 | 
						|
        // a status error. Now we will only report EFI_SUCCESS since Uhc
 | 
						|
        // driver will be disconnected at the second time.(pls see
 | 
						|
        // CoreDisconnectController for details)
 | 
						|
        //
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      UsbController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (UsbIo);
 | 
						|
      UsbIoDevice   = UsbController->UsbDevice;
 | 
						|
      HubController = UsbController->Parent;
 | 
						|
      UsbDeviceDeConfiguration (UsbIoDevice);
 | 
						|
      for (Index2 = 0; Index2 < HubController->DownstreamPorts; Index2++) {
 | 
						|
        if (HubController->Children[Index2] == UsbIoDevice) {
 | 
						|
          HubController->Children[Index2] = NULL;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get the USB_BUS_CONTROLLER_DEVICE
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  &mUsbBusProtocolGuid,
 | 
						|
                  (VOID **) &UsbIdentifier,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbBusController = USB_BUS_CONTROLLER_DEVICE_FROM_THIS (UsbIdentifier);
 | 
						|
 | 
						|
  //
 | 
						|
  // Stop USB Host Controller
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Report Status Code here since we will reset the host controller
 | 
						|
  //
 | 
						|
  ReportUsbStatusCode (
 | 
						|
    UsbBusController,
 | 
						|
    EFI_PROGRESS_CODE,
 | 
						|
    EFI_IO_BUS_USB | EFI_IOB_PC_RESET
 | 
						|
    );
 | 
						|
 | 
						|
  UsbVirtualHcSetState (
 | 
						|
    UsbBusController,
 | 
						|
    EfiUsbHcStateHalt
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Deconfiguration all its devices
 | 
						|
  //
 | 
						|
  Root              = UsbBusController->Root;
 | 
						|
  RootHubController = Root->UsbController[0];
 | 
						|
 | 
						|
  gBS->CloseEvent (RootHubController->HubNotify);
 | 
						|
 | 
						|
  for (Index2 = 0; Index2 < RootHubController->DownstreamPorts; Index2++) {
 | 
						|
    if (RootHubController->Children[Index2]) {
 | 
						|
      UsbDeviceDeConfiguration (RootHubController->Children[Index2]);
 | 
						|
      RootHubController->Children[Index2] = NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->FreePool (RootHubController);
 | 
						|
  gBS->FreePool (Root);
 | 
						|
 | 
						|
  //
 | 
						|
  // Uninstall USB Bus Protocol
 | 
						|
  //
 | 
						|
  gBS->UninstallProtocolInterface (
 | 
						|
        Controller,
 | 
						|
        &mUsbBusProtocolGuid,
 | 
						|
        &UsbBusController->BusIdentify
 | 
						|
        );
 | 
						|
 | 
						|
  //
 | 
						|
  // Close USB_HC_PROTOCOL & DEVICE_PATH_PROTOCOL
 | 
						|
  // Opened by this Controller
 | 
						|
  //
 | 
						|
  if (UsbBusController->Hc2ProtocolSupported) {
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          Controller,
 | 
						|
          &gEfiUsb2HcProtocolGuid,
 | 
						|
          This->DriverBindingHandle,
 | 
						|
          Controller
 | 
						|
          );
 | 
						|
  } else {
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          Controller,
 | 
						|
          &gEfiUsbHcProtocolGuid,
 | 
						|
          This->DriverBindingHandle,
 | 
						|
          Controller
 | 
						|
          );
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->CloseProtocol (
 | 
						|
        Controller,
 | 
						|
        &gEfiDevicePathProtocolGuid,
 | 
						|
        This->DriverBindingHandle,
 | 
						|
        Controller
 | 
						|
        );
 | 
						|
 | 
						|
  gBS->FreePool (UsbBusController);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
//
 | 
						|
// USB Device Configuration
 | 
						|
//
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
UsbDeviceConfiguration (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE     *ParentHubController,
 | 
						|
  IN EFI_HANDLE                   HostController,
 | 
						|
  IN UINT8                        ParentPort,
 | 
						|
  IN USB_IO_DEVICE                *UsbIoDevice
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Configurate a new device attached to the usb bus
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    ParentHubController   -   Parent Hub which this device is connected.
 | 
						|
    HostController        -   Host Controller handle
 | 
						|
    ParentPort            -   Parent Hub port which this device is connected.
 | 
						|
    UsbIoDevice           -   The device to be configured.
 | 
						|
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
    EFI_OUT_OF_RESOURCES
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8                     DevAddress;
 | 
						|
  UINT8                     Index;
 | 
						|
  EFI_STATUS                Result;
 | 
						|
  UINT32                    Status;
 | 
						|
  CHAR16                    *StrManufacturer;
 | 
						|
  CHAR16                    *StrProduct;
 | 
						|
  CHAR16                    *StrSerialNumber;
 | 
						|
  EFI_USB_IO_PROTOCOL       *UsbIo;
 | 
						|
  UINT8                     NumOfInterface;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *FirstController;
 | 
						|
  USB_BUS_CONTROLLER_DEVICE *UsbBusDev;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *UsbIoController;
 | 
						|
 | 
						|
  UsbBusDev = UsbIoDevice->BusController;
 | 
						|
 | 
						|
  UsbSetTransactionTranslator (
 | 
						|
    ParentHubController,
 | 
						|
    ParentPort,
 | 
						|
    UsbIoDevice
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Since a USB device must have at least on interface,
 | 
						|
  // so create this instance first
 | 
						|
  //
 | 
						|
  FirstController                   = CreateUsbIoControllerDevice ();
 | 
						|
  FirstController->UsbDevice        = UsbIoDevice;
 | 
						|
  UsbIoDevice->UsbController[0]     = FirstController;
 | 
						|
  FirstController->InterfaceNumber  = 0;
 | 
						|
  FirstController->ParentPort       = ParentPort;
 | 
						|
  FirstController->Parent           = ParentHubController;
 | 
						|
  FirstController->HostController   = HostController;
 | 
						|
 | 
						|
  InitializeUsbIoInstance (FirstController);
 | 
						|
 | 
						|
  DEBUG ((gUSBDebugLevel, "Configuration Usb Device at 0x%x...\n", ParentPort));
 | 
						|
 | 
						|
  //
 | 
						|
  // Ensure we used the correctly USB I/O instance
 | 
						|
  //
 | 
						|
  UsbIo = &FirstController->UsbIo;
 | 
						|
 | 
						|
  ParentPortReset (FirstController, FALSE, 0);
 | 
						|
 | 
						|
  //
 | 
						|
  // First retrieve the 1st 8 bytes of
 | 
						|
  // in order to get the MaxPacketSize for Endpoint 0
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < 3; Index++) {
 | 
						|
 | 
						|
    UsbIoDevice->DeviceDescriptor.MaxPacketSize0 = 8;
 | 
						|
 | 
						|
    gBS->Stall (100 * 1000);
 | 
						|
 | 
						|
    Result = UsbGetDescriptor (
 | 
						|
              UsbIo,
 | 
						|
              (USB_DT_DEVICE << 8),
 | 
						|
              0,
 | 
						|
              8,
 | 
						|
              &UsbIoDevice->DeviceDescriptor,
 | 
						|
              &Status
 | 
						|
              );
 | 
						|
    if (!EFI_ERROR (Result)) {
 | 
						|
      DEBUG (
 | 
						|
        (gUSBDebugLevel,
 | 
						|
        "Get Device Descriptor Success, MaxPacketSize0 = 0x%x\n",
 | 
						|
        UsbIoDevice->DeviceDescriptor.MaxPacketSize0)
 | 
						|
        );
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  if (Index == 3) {
 | 
						|
    ReportUsbStatusCode (
 | 
						|
      UsbBusDev,
 | 
						|
      EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | 
						|
      EFI_IO_BUS_USB | EFI_IOB_EC_READ_ERROR
 | 
						|
      );
 | 
						|
    DEBUG ((gUSBErrorLevel, "Get Device Descriptor Fail when configing\n"));
 | 
						|
    gBS->FreePool (FirstController);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  DevAddress = UsbAllocateAddress (UsbIoDevice->BusController->AddressPool);
 | 
						|
  if (DevAddress == 0) {
 | 
						|
    DEBUG ((gUSBErrorLevel, "Cannot allocate address\n"));
 | 
						|
    gBS->FreePool (FirstController);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Result = UsbSetDeviceAddress (UsbIo, DevAddress, &Status);
 | 
						|
 | 
						|
  if (EFI_ERROR (Result)) {
 | 
						|
    DEBUG ((gUSBErrorLevel, "Set address error\n"));
 | 
						|
    ReportUsbStatusCode (
 | 
						|
      UsbBusDev,
 | 
						|
      EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | 
						|
      EFI_IO_BUS_USB | EFI_IOB_EC_WRITE_ERROR
 | 
						|
      );
 | 
						|
 | 
						|
    UsbFreeAddress (
 | 
						|
      DevAddress,
 | 
						|
      UsbIoDevice->BusController->AddressPool
 | 
						|
      );
 | 
						|
 | 
						|
    gBS->FreePool (FirstController);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbIoDevice->DeviceAddress = DevAddress;
 | 
						|
 | 
						|
  //
 | 
						|
  // SetAddress Complete Time by Spec, Max 50ms
 | 
						|
  //
 | 
						|
  gBS->Stall (10 * 1000);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the whole device descriptor
 | 
						|
  //
 | 
						|
  Result = UsbGetDescriptor (
 | 
						|
            UsbIo,
 | 
						|
            (USB_DT_DEVICE << 8),
 | 
						|
            0,
 | 
						|
            sizeof (EFI_USB_DEVICE_DESCRIPTOR),
 | 
						|
            &UsbIoDevice->DeviceDescriptor,
 | 
						|
            &Status
 | 
						|
            );
 | 
						|
 | 
						|
  if (EFI_ERROR (Result)) {
 | 
						|
    DEBUG ((gUSBErrorLevel, "Get whole Device Descriptor error\n"));
 | 
						|
    ReportUsbStatusCode (
 | 
						|
      UsbBusDev,
 | 
						|
      EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | 
						|
      EFI_IO_BUS_USB | EFI_IOB_EC_READ_ERROR
 | 
						|
      );
 | 
						|
    UsbFreeAddress (
 | 
						|
      DevAddress,
 | 
						|
      UsbIoDevice->BusController->AddressPool
 | 
						|
      );
 | 
						|
 | 
						|
    gBS->FreePool (FirstController);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get & parse all configurations for this device, including
 | 
						|
  // all configuration descriptors, all interface descriptors, all
 | 
						|
  // endpoint descriptors
 | 
						|
  //
 | 
						|
  Result = UsbGetAllConfigurations (UsbIoDevice);
 | 
						|
 | 
						|
  if (EFI_ERROR (Result)) {
 | 
						|
    DEBUG ((gUSBErrorLevel, "Failed to get device configuration\n"));
 | 
						|
    ReportUsbStatusCode (
 | 
						|
      UsbBusDev,
 | 
						|
      EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | 
						|
      EFI_IO_BUS_USB | EFI_IOB_EC_READ_ERROR
 | 
						|
      );
 | 
						|
    UsbFreeAddress (
 | 
						|
      DevAddress,
 | 
						|
      UsbIoDevice->BusController->AddressPool
 | 
						|
      );
 | 
						|
 | 
						|
    gBS->FreePool (FirstController);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Set the 1st configuration value
 | 
						|
  //
 | 
						|
  Result = UsbSetDefaultConfiguration (UsbIoDevice);
 | 
						|
  if (EFI_ERROR (Result)) {
 | 
						|
    DEBUG ((gUSBErrorLevel, "Failed to set device configuration\n"));
 | 
						|
    ReportUsbStatusCode (
 | 
						|
      UsbBusDev,
 | 
						|
      EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | 
						|
      EFI_IO_BUS_USB | EFI_IOB_EC_WRITE_ERROR
 | 
						|
      );
 | 
						|
    UsbFreeAddress (
 | 
						|
      DevAddress,
 | 
						|
      UsbIoDevice->BusController->AddressPool
 | 
						|
      );
 | 
						|
 | 
						|
    gBS->FreePool (FirstController);
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbIoDevice->IsConfigured = TRUE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get all string table if applicable
 | 
						|
  //
 | 
						|
  Result = UsbGetStringtable (UsbIoDevice);
 | 
						|
  if (EFI_ERROR (Result)) {
 | 
						|
    DEBUG ((gUSBDebugLevel, "Device doesn't support string table\n"));
 | 
						|
  } else {
 | 
						|
 | 
						|
    StrManufacturer = NULL;
 | 
						|
    UsbIo->UsbGetStringDescriptor (
 | 
						|
            UsbIo,
 | 
						|
            UsbIoDevice->LangID[0],
 | 
						|
            (UsbIoDevice->DeviceDescriptor).StrManufacturer,
 | 
						|
            &StrManufacturer
 | 
						|
            );
 | 
						|
 | 
						|
    StrProduct = NULL;
 | 
						|
    UsbIo->UsbGetStringDescriptor (
 | 
						|
            UsbIo,
 | 
						|
            UsbIoDevice->LangID[0],
 | 
						|
            (UsbIoDevice->DeviceDescriptor).StrProduct,
 | 
						|
            &StrProduct
 | 
						|
            );
 | 
						|
 | 
						|
    StrSerialNumber = NULL;
 | 
						|
    UsbIo->UsbGetStringDescriptor (
 | 
						|
            UsbIo,
 | 
						|
            UsbIoDevice->LangID[0],
 | 
						|
            (UsbIoDevice->DeviceDescriptor).StrSerialNumber,
 | 
						|
            &StrSerialNumber
 | 
						|
            );
 | 
						|
 | 
						|
    if (StrManufacturer) {
 | 
						|
      gBS->FreePool (StrManufacturer);
 | 
						|
    }
 | 
						|
 | 
						|
    if (StrProduct) {
 | 
						|
      gBS->FreePool (StrProduct);
 | 
						|
    }
 | 
						|
 | 
						|
    if (StrSerialNumber) {
 | 
						|
      gBS->FreePool (StrSerialNumber);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Create USB_IO_CONTROLLER_DEVICE for
 | 
						|
  // each detected interface
 | 
						|
  //
 | 
						|
  FirstController->CurrentConfigValue =
 | 
						|
  UsbIoDevice->ActiveConfig->CongfigDescriptor.ConfigurationValue;
 | 
						|
 | 
						|
  NumOfInterface                      =
 | 
						|
  UsbIoDevice->ActiveConfig->CongfigDescriptor.NumInterfaces;
 | 
						|
  UsbIoDevice->NumOfControllers       = NumOfInterface;
 | 
						|
 | 
						|
  Result = InitUsbIoController (FirstController);
 | 
						|
  if (EFI_ERROR (Result)) {
 | 
						|
    ReportUsbStatusCode (
 | 
						|
      UsbBusDev,
 | 
						|
      EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | 
						|
      EFI_IO_BUS_USB | EFI_IOB_EC_INTERFACE_ERROR
 | 
						|
      );
 | 
						|
    gBS->FreePool (FirstController);
 | 
						|
    UsbIoDevice->UsbController[0] = NULL;
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 1; Index < NumOfInterface; Index++) {
 | 
						|
    UsbIoController                     = CreateUsbIoControllerDevice ();
 | 
						|
    UsbIoController->UsbDevice          = UsbIoDevice;
 | 
						|
    UsbIoController->CurrentConfigValue =
 | 
						|
    UsbIoDevice->ActiveConfig->CongfigDescriptor.ConfigurationValue;
 | 
						|
    UsbIoController->InterfaceNumber    = Index;
 | 
						|
    UsbIoDevice->UsbController[Index]   = UsbIoController;
 | 
						|
    UsbIoController->ParentPort         = ParentPort;
 | 
						|
    UsbIoController->Parent             = ParentHubController;
 | 
						|
    UsbIoController->HostController     = HostController;
 | 
						|
 | 
						|
    //
 | 
						|
    // First copy the USB_IO Protocol instance
 | 
						|
    //
 | 
						|
    CopyMem (
 | 
						|
      &UsbIoController->UsbIo,
 | 
						|
      UsbIo,
 | 
						|
      sizeof (EFI_USB_IO_PROTOCOL)
 | 
						|
      );
 | 
						|
 | 
						|
    Result = InitUsbIoController (UsbIoController);
 | 
						|
    if (EFI_ERROR (Result)) {
 | 
						|
      ReportUsbStatusCode (
 | 
						|
        UsbBusDev,
 | 
						|
        EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | 
						|
        EFI_IO_BUS_USB | EFI_IOB_EC_INTERFACE_ERROR
 | 
						|
        );
 | 
						|
      gBS->FreePool (UsbIoController);
 | 
						|
      UsbIoDevice->UsbController[Index] = NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
//
 | 
						|
// USB Device DeConfiguration
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
UsbDeviceDeConfiguration (
 | 
						|
  IN USB_IO_DEVICE     *UsbIoDevice
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Remove Device, Device Handles, Uninstall Protocols.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    UsbIoDevice     -   The device to be deconfigured.
 | 
						|
 | 
						|
  Returns: 
 | 
						|
    EFI_SUCCESS
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *UsbController;
 | 
						|
  UINT8                     index;
 | 
						|
  USB_IO_DEVICE             *ChildDevice;
 | 
						|
  UINT8                     Index;
 | 
						|
  EFI_USB_IO_PROTOCOL       *UsbIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // Double check UsbIoDevice exists
 | 
						|
  //
 | 
						|
  if (UsbIoDevice == NULL) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbUnsetTransactionTranslator (UsbIoDevice);
 | 
						|
 | 
						|
  for (index = 0; index < UsbIoDevice->NumOfControllers; index++) {
 | 
						|
    //
 | 
						|
    // Check if it is a hub, if so, de configuration all its
 | 
						|
    // downstream ports
 | 
						|
    //
 | 
						|
    UsbController = UsbIoDevice->UsbController[index];
 | 
						|
 | 
						|
    //
 | 
						|
    // Check the controller pointer
 | 
						|
    //
 | 
						|
    if (UsbController == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if (UsbController->IsUsbHub) {
 | 
						|
 | 
						|
      DEBUG ((gUSBDebugLevel, "Hub Deconfig, First Deconfig its downstream ports\n"));
 | 
						|
 | 
						|
      //
 | 
						|
      // First Remove interrupt transfer request for the status
 | 
						|
      // change port
 | 
						|
      //
 | 
						|
      UsbIo = &UsbController->UsbIo;
 | 
						|
      UsbIo->UsbAsyncInterruptTransfer (
 | 
						|
              UsbIo,
 | 
						|
              UsbController->HubEndpointAddress,
 | 
						|
              FALSE,
 | 
						|
              0,
 | 
						|
              0,
 | 
						|
              NULL,
 | 
						|
              NULL
 | 
						|
              );
 | 
						|
 | 
						|
      if (NULL != UsbController->HubNotify) {
 | 
						|
        gBS->CloseEvent (UsbController->HubNotify);
 | 
						|
      }
 | 
						|
 | 
						|
      for (Index = 0; Index < UsbController->DownstreamPorts; Index++) {
 | 
						|
        if (UsbController->Children[Index]) {
 | 
						|
          ChildDevice = UsbController->Children[Index];
 | 
						|
          UsbDeviceDeConfiguration (ChildDevice);
 | 
						|
          UsbController->Children[Index] = NULL;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // If the controller is managed by a device driver, we need to
 | 
						|
    // disconnect them
 | 
						|
    //
 | 
						|
    if (UsbController->IsManagedByDriver) {
 | 
						|
      gBS->DisconnectController (
 | 
						|
            UsbController->Handle,
 | 
						|
            NULL,
 | 
						|
            NULL
 | 
						|
            );
 | 
						|
    }
 | 
						|
    
 | 
						|
    //
 | 
						|
    // remove child handle reference to the USB_HC_PROTOCOL
 | 
						|
    //
 | 
						|
    if (UsbIoDevice->BusController->Hc2ProtocolSupported) {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
            UsbController->HostController,
 | 
						|
            &gEfiUsb2HcProtocolGuid,
 | 
						|
            gUsbBusDriverBinding.DriverBindingHandle,
 | 
						|
            UsbController->Handle
 | 
						|
            );
 | 
						|
    } else {
 | 
						|
      gBS->CloseProtocol (
 | 
						|
            UsbController->HostController,
 | 
						|
            &gEfiUsbHcProtocolGuid,
 | 
						|
            gUsbBusDriverBinding.DriverBindingHandle,
 | 
						|
            UsbController->Handle
 | 
						|
            );
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Uninstall EFI_USB_IO_PROTOCOL & DEVICE_PATH_PROTOCOL
 | 
						|
    // installed on this handle
 | 
						|
    //
 | 
						|
    gBS->UninstallMultipleProtocolInterfaces (
 | 
						|
          UsbController->Handle,
 | 
						|
          &gEfiDevicePathProtocolGuid,
 | 
						|
          UsbController->DevicePath,
 | 
						|
          &gEfiUsbIoProtocolGuid,
 | 
						|
          &UsbController->UsbIo,
 | 
						|
          NULL
 | 
						|
          );
 | 
						|
 | 
						|
    if (UsbController->DevicePath != NULL) {
 | 
						|
      gBS->FreePool (UsbController->DevicePath);
 | 
						|
    }
 | 
						|
 | 
						|
    gBS->FreePool (UsbController);
 | 
						|
    UsbIoDevice->UsbController[index] = NULL;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Free address for later use
 | 
						|
  //
 | 
						|
  UsbFreeAddress (
 | 
						|
    UsbIoDevice->DeviceAddress,
 | 
						|
    UsbIoDevice->BusController->AddressPool
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Free all resouces allocated for all its configurations
 | 
						|
  //
 | 
						|
  UsbDestroyAllConfiguration (UsbIoDevice);
 | 
						|
 | 
						|
  if (UsbIoDevice) {
 | 
						|
    gBS->FreePool (UsbIoDevice);
 | 
						|
    UsbIoDevice = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
//
 | 
						|
// After interrupt complete, this function will be called,
 | 
						|
// This function need to be well-defined later
 | 
						|
//
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
OnHubInterruptComplete (
 | 
						|
  IN  VOID          *Data,
 | 
						|
  IN  UINTN         DataLength,
 | 
						|
  IN  VOID          *Context,
 | 
						|
  IN  UINT32        Result
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Whenever hub interrupt occurs, this routine will be called to check
 | 
						|
    which event happens.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    Data          -   Hub interrupt transfer data.
 | 
						|
    DataLength    -   The length of the Data.
 | 
						|
    Context       -   Hub Controller Device.
 | 
						|
    Result        -   Hub interrupt transfer status.
 | 
						|
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *HubController;
 | 
						|
  UINT8                     Index;
 | 
						|
  UINT8                     *ptr;
 | 
						|
  EFI_USB_IO_PROTOCOL       *UsbIo;
 | 
						|
  UINT32                    UsbResult;
 | 
						|
  BOOLEAN                   Disconnected;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  HubController = (USB_IO_CONTROLLER_DEVICE *) Context;
 | 
						|
  UsbIo         = &HubController->UsbIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // If something error in this interrupt transfer,
 | 
						|
  //
 | 
						|
  if (Result != EFI_USB_NOERROR) {
 | 
						|
    if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
 | 
						|
      UsbClearEndpointHalt (
 | 
						|
        UsbIo,
 | 
						|
        HubController->HubEndpointAddress,
 | 
						|
        &UsbResult
 | 
						|
        );
 | 
						|
    }
 | 
						|
    
 | 
						|
    //
 | 
						|
    // Delete & Submit this interrupt again
 | 
						|
    //
 | 
						|
    UsbIo->UsbAsyncInterruptTransfer (
 | 
						|
            UsbIo,
 | 
						|
            HubController->HubEndpointAddress,
 | 
						|
            FALSE,
 | 
						|
            0,
 | 
						|
            0,
 | 
						|
            NULL,
 | 
						|
            NULL
 | 
						|
            );
 | 
						|
 | 
						|
    //
 | 
						|
    // try to detect if the hub itself was disconnected or not
 | 
						|
    //
 | 
						|
    Status = IsDeviceDisconnected (
 | 
						|
              HubController,
 | 
						|
              &Disconnected
 | 
						|
              );
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status) && Disconnected == TRUE) {
 | 
						|
      DEBUG ((gUSBErrorLevel, "Hub is disconnected\n"));
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Hub ports < 7
 | 
						|
    //
 | 
						|
    UsbIo->UsbAsyncInterruptTransfer (
 | 
						|
            UsbIo,
 | 
						|
            HubController->HubEndpointAddress,
 | 
						|
            TRUE,
 | 
						|
            100,
 | 
						|
            1,
 | 
						|
            OnHubInterruptComplete,
 | 
						|
            HubController
 | 
						|
            );
 | 
						|
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DataLength == 0 || Data == NULL) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Scan which port has status change
 | 
						|
  // Bit 0 stands for hub itself, other bit stands for
 | 
						|
  // the corresponding port
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < DataLength * 8; Index++) {
 | 
						|
    ptr = (UINT8 *) Data + Index / 8;
 | 
						|
    if ((*ptr) & (1 << (Index & 0x7))) {
 | 
						|
      HubController->StatusChangePort = Index;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Signal hub notify event
 | 
						|
  //
 | 
						|
  gBS->SignalEvent (HubController->HubNotify);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
//
 | 
						|
// USB Root Hub Enumerator
 | 
						|
//
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
RootHubEnumeration (
 | 
						|
  IN EFI_EVENT     Event,
 | 
						|
  IN VOID          *Context
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    This is USB RootHub enumerator
 | 
						|
 | 
						|
  Arguments:
 | 
						|
  
 | 
						|
    Event   -   Indicating which event is signaled
 | 
						|
    Context -  actually it is a USB_IO_DEVICE
 | 
						|
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    VOID
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *HubController;
 | 
						|
  EFI_USB_PORT_STATUS       HubPortStatus;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINT8                     Index;
 | 
						|
  USB_IO_DEVICE             *UsbIoDev;
 | 
						|
  USB_BUS_CONTROLLER_DEVICE *UsbBusDev;
 | 
						|
  EFI_HANDLE                HostController;
 | 
						|
  USB_IO_DEVICE             *OldUsbIoDevice;
 | 
						|
  USB_IO_DEVICE             *NewDevice;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *NewController;
 | 
						|
  UINT8                     Index2;
 | 
						|
  EFI_USB_IO_PROTOCOL       *UsbIo;
 | 
						|
 | 
						|
  HubController   = (USB_IO_CONTROLLER_DEVICE *) Context;
 | 
						|
  HostController  = HubController->HostController;
 | 
						|
  UsbBusDev       = HubController->UsbDevice->BusController;
 | 
						|
 | 
						|
  //
 | 
						|
  // Root hub has the address 1
 | 
						|
  //
 | 
						|
  UsbIoDev = HubController->UsbDevice;
 | 
						|
 | 
						|
  for (Index = 0; Index < HubController->DownstreamPorts; Index++) {
 | 
						|
 | 
						|
    UsbVirtualHcGetRootHubPortStatus (
 | 
						|
      UsbBusDev,
 | 
						|
      Index,
 | 
						|
      (EFI_USB_PORT_STATUS *) &HubPortStatus
 | 
						|
      );
 | 
						|
 | 
						|
    if (!IsPortConnectChange (HubPortStatus.PortChangeStatus)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Clear root hub status change status
 | 
						|
    //
 | 
						|
    UsbVirtualHcClearRootHubPortFeature (
 | 
						|
      UsbBusDev,
 | 
						|
      Index,
 | 
						|
      EfiUsbPortConnectChange
 | 
						|
      );
 | 
						|
 | 
						|
    gBS->Stall (100 * 1000);
 | 
						|
 | 
						|
    UsbVirtualHcGetRootHubPortStatus (
 | 
						|
      UsbBusDev,
 | 
						|
      Index,
 | 
						|
      (EFI_USB_PORT_STATUS *) &HubPortStatus
 | 
						|
      );
 | 
						|
 | 
						|
    if (IsPortConnect (HubPortStatus.PortStatus)) {
 | 
						|
        
 | 
						|
      //
 | 
						|
      // There is something connected to this port
 | 
						|
      //
 | 
						|
      DEBUG ((gUSBDebugLevel, "Something connected to Root Hub at Port0x%x\n", Index));
 | 
						|
 | 
						|
      ReportUsbStatusCode (
 | 
						|
        UsbBusDev,
 | 
						|
        EFI_PROGRESS_CODE,
 | 
						|
        EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG
 | 
						|
        );
 | 
						|
      //
 | 
						|
      // if there is something physically detached, but still logically
 | 
						|
      // attached...
 | 
						|
      //
 | 
						|
      OldUsbIoDevice = HubController->Children[Index];
 | 
						|
 | 
						|
      if (NULL != OldUsbIoDevice) {
 | 
						|
        UsbDeviceDeConfiguration (OldUsbIoDevice);
 | 
						|
        HubController->Children[Index] = NULL;
 | 
						|
      }
 | 
						|
 | 
						|
      NewDevice = AllocateZeroPool (sizeof (USB_IO_DEVICE));
 | 
						|
      if (NewDevice == NULL) {
 | 
						|
        return ;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Initialize some fields by copying data from
 | 
						|
      // its parents
 | 
						|
      //
 | 
						|
      NewDevice->DeviceDescriptor.MaxPacketSize0  = 8;
 | 
						|
      NewDevice->BusController                    = UsbIoDev->BusController;
 | 
						|
 | 
						|
      //
 | 
						|
      // Process of identify device speed
 | 
						|
      //
 | 
						|
      Status = IdentifyDeviceSpeed (
 | 
						|
                 UsbBusDev, 
 | 
						|
                 NewDevice, 
 | 
						|
                 Index
 | 
						|
                 );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        gBS->FreePool (NewDevice);
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Configure that device
 | 
						|
      //
 | 
						|
      Status = UsbDeviceConfiguration (
 | 
						|
                HubController,
 | 
						|
                HostController,
 | 
						|
                Index,
 | 
						|
                NewDevice
 | 
						|
                );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        gBS->FreePool (NewDevice);
 | 
						|
        return ;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Add this device to the usb bus tree
 | 
						|
      //
 | 
						|
      HubController->Children[Index] = NewDevice;
 | 
						|
 | 
						|
      for (Index2 = 0; Index2 < NewDevice->NumOfControllers; Index2++) {
 | 
						|
        //
 | 
						|
        // If this device is hub, add to the hub index
 | 
						|
        //
 | 
						|
        NewController = NewDevice->UsbController[Index2];
 | 
						|
 | 
						|
        Status = gBS->ConnectController (
 | 
						|
                        NewController->Handle,
 | 
						|
                        NULL,
 | 
						|
                        NULL,
 | 
						|
                        TRUE
 | 
						|
                        );
 | 
						|
        //
 | 
						|
        // If connect success, we need to disconnect when
 | 
						|
        // stop the controller, otherwise we need not call
 | 
						|
        // gBS->DisconnectController ()
 | 
						|
        // This is used by those usb devices we don't plan
 | 
						|
        // to support. We can allocate
 | 
						|
        // controller handles for them, but we don't have
 | 
						|
        // device drivers to manage them.
 | 
						|
        //
 | 
						|
        NewController->IsManagedByDriver = (BOOLEAN) (!EFI_ERROR (Status));
 | 
						|
 | 
						|
        if (IsHub (NewController)) {
 | 
						|
 | 
						|
          NewController->IsUsbHub = TRUE;
 | 
						|
 | 
						|
          //
 | 
						|
          // Configure Hub Controller
 | 
						|
          //
 | 
						|
          Status = DoHubConfig (NewController);
 | 
						|
          if (EFI_ERROR (Status)) {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
          //
 | 
						|
          // Create an event to do hub enumeration
 | 
						|
          //
 | 
						|
          gBS->CreateEvent (
 | 
						|
                EFI_EVENT_NOTIFY_SIGNAL,
 | 
						|
                EFI_TPL_CALLBACK,
 | 
						|
                HubEnumeration,
 | 
						|
                NewController,
 | 
						|
                &NewController->HubNotify
 | 
						|
                );
 | 
						|
 | 
						|
          //
 | 
						|
          // Add request to do query hub status
 | 
						|
          // change endpoint
 | 
						|
          // Hub ports < 7
 | 
						|
          //
 | 
						|
          UsbIo = &NewController->UsbIo;
 | 
						|
          UsbIo->UsbAsyncInterruptTransfer (
 | 
						|
                  UsbIo,
 | 
						|
                  NewController->HubEndpointAddress,
 | 
						|
                  TRUE,
 | 
						|
                  100,
 | 
						|
                  1,
 | 
						|
                  OnHubInterruptComplete,
 | 
						|
                  NewController
 | 
						|
                  );
 | 
						|
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Something disconnected from USB root hub
 | 
						|
      //
 | 
						|
      DEBUG ((gUSBDebugLevel, "Something disconnected from Root Hub at Port0x%x\n", Index));
 | 
						|
 | 
						|
      OldUsbIoDevice = HubController->Children[Index];
 | 
						|
 | 
						|
      UsbDeviceDeConfiguration (OldUsbIoDevice);
 | 
						|
 | 
						|
      HubController->Children[Index] = NULL;
 | 
						|
 | 
						|
      UsbVirtualHcClearRootHubPortFeature (
 | 
						|
        UsbBusDev,
 | 
						|
        Index,
 | 
						|
        EfiUsbPortEnableChange
 | 
						|
        );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
//
 | 
						|
// USB Root Hub Enumerator
 | 
						|
//
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
HubEnumeration (
 | 
						|
  IN EFI_EVENT     Event,
 | 
						|
  IN VOID          *Context
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    This is Usb Hub enumerator
 | 
						|
 | 
						|
  Arguments:
 | 
						|
  
 | 
						|
    Event    -   Indicating which event is signaled
 | 
						|
    Context  -  actually it is a USB_IO_DEVICE
 | 
						|
 | 
						|
  Returns:
 | 
						|
 | 
						|
    VOID
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *HubController;
 | 
						|
  EFI_USB_PORT_STATUS       HubPortStatus;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  USB_BUS_CONTROLLER_DEVICE *UsbBusDev;
 | 
						|
  EFI_HANDLE                HostController;
 | 
						|
  USB_IO_DEVICE             *OldUsbIoDevice;
 | 
						|
  USB_IO_DEVICE             *NewDevice;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *NewController;
 | 
						|
  UINT8                     Index2;
 | 
						|
  EFI_USB_IO_PROTOCOL       *UsbIo;
 | 
						|
  UINT8                     StatusChangePort;
 | 
						|
  UINT8                     Number;
 | 
						|
 | 
						|
  HubController   = (USB_IO_CONTROLLER_DEVICE *) Context;
 | 
						|
  HostController  = HubController->HostController;
 | 
						|
  UsbBusDev       = HubController->UsbDevice->BusController;
 | 
						|
 | 
						|
  //
 | 
						|
  // Event from Hub, Get the hub controller handle
 | 
						|
  //
 | 
						|
  //
 | 
						|
  // Get the status change endpoint
 | 
						|
  //
 | 
						|
  StatusChangePort = HubController->StatusChangePort;
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear HubController Status Change Bit
 | 
						|
  //
 | 
						|
  HubController->StatusChangePort = 0;
 | 
						|
 | 
						|
  if (StatusChangePort == 0) {
 | 
						|
    //
 | 
						|
    // Hub changes, we don't handle here
 | 
						|
    //
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Check which event took place at that port
 | 
						|
  //
 | 
						|
  UsbIo = &HubController->UsbIo;
 | 
						|
  Status = HubGetPortStatus (
 | 
						|
            UsbIo,
 | 
						|
            StatusChangePort,
 | 
						|
            (UINT32 *) &HubPortStatus
 | 
						|
            );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Clear some change status
 | 
						|
  //
 | 
						|
  if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_ENABLE) {
 | 
						|
    //
 | 
						|
    // Clear Hub port enable change
 | 
						|
    //
 | 
						|
    DEBUG ((gUSBDebugLevel, "Port Enable Change\n"));
 | 
						|
    HubClearPortFeature (
 | 
						|
      UsbIo,
 | 
						|
      StatusChangePort,
 | 
						|
      EfiUsbPortEnableChange
 | 
						|
      );
 | 
						|
 | 
						|
    HubGetPortStatus (
 | 
						|
      UsbIo,
 | 
						|
      StatusChangePort,
 | 
						|
      (UINT32 *) &HubPortStatus
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) {
 | 
						|
    //
 | 
						|
    // Clear Hub reset change
 | 
						|
    //
 | 
						|
    DEBUG ((gUSBDebugLevel, "Port Reset Change\n"));
 | 
						|
    HubClearPortFeature (
 | 
						|
      UsbIo,
 | 
						|
      StatusChangePort,
 | 
						|
      EfiUsbPortResetChange
 | 
						|
      );
 | 
						|
 | 
						|
    HubGetPortStatus (
 | 
						|
      UsbIo,
 | 
						|
      StatusChangePort,
 | 
						|
      (UINT32 *) &HubPortStatus
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_OVERCURRENT) {
 | 
						|
    //
 | 
						|
    // Clear Hub overcurrent change
 | 
						|
    //
 | 
						|
    DEBUG ((gUSBDebugLevel, "Port Overcurrent Change\n"));
 | 
						|
    HubClearPortFeature (
 | 
						|
      UsbIo,
 | 
						|
      StatusChangePort,
 | 
						|
      EfiUsbPortOverCurrentChange
 | 
						|
      );
 | 
						|
 | 
						|
    HubGetPortStatus (
 | 
						|
      UsbIo,
 | 
						|
      StatusChangePort,
 | 
						|
      (UINT32 *) &HubPortStatus
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  if (IsPortConnectChange (HubPortStatus.PortChangeStatus)) {
 | 
						|
    //
 | 
						|
    // First clear port connection change
 | 
						|
    //
 | 
						|
    DEBUG ((gUSBDebugLevel, "Port Connection Change\n"));
 | 
						|
    HubClearPortFeature (
 | 
						|
      UsbIo,
 | 
						|
      StatusChangePort,
 | 
						|
      EfiUsbPortConnectChange
 | 
						|
      );
 | 
						|
 | 
						|
    HubGetPortStatus (
 | 
						|
      UsbIo,
 | 
						|
      StatusChangePort,
 | 
						|
      (UINT32 *) &HubPortStatus
 | 
						|
      );
 | 
						|
 | 
						|
    if (IsPortConnect (HubPortStatus.PortStatus)) {
 | 
						|
 | 
						|
      DEBUG ((gUSBDebugLevel, "New Device Connect on Hub port \n"));
 | 
						|
 | 
						|
      ReportUsbStatusCode (
 | 
						|
        UsbBusDev,
 | 
						|
        EFI_PROGRESS_CODE,
 | 
						|
        EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG
 | 
						|
        );
 | 
						|
 | 
						|
      //
 | 
						|
      // if there is something physically detached, but still logically
 | 
						|
      // attached...
 | 
						|
      //
 | 
						|
      OldUsbIoDevice = HubController->Children[StatusChangePort - 1];
 | 
						|
 | 
						|
      if (NULL != OldUsbIoDevice) {
 | 
						|
        UsbDeviceDeConfiguration (OldUsbIoDevice);
 | 
						|
        HubController->Children[StatusChangePort - 1] = NULL;
 | 
						|
      }
 | 
						|
 | 
						|
      NewDevice = AllocateZeroPool (sizeof (USB_IO_DEVICE));
 | 
						|
      if (NewDevice == NULL) {
 | 
						|
        return ;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Initialize some fields
 | 
						|
      //
 | 
						|
      NewDevice->DeviceDescriptor.MaxPacketSize0  = 8;
 | 
						|
      NewDevice->BusController                    = HubController->UsbDevice->BusController;
 | 
						|
 | 
						|
      //
 | 
						|
      // There is something connected to this port,
 | 
						|
      // reset that port
 | 
						|
      //
 | 
						|
      // Disable the enable bit in port status
 | 
						|
      //
 | 
						|
      HubClearPortFeature (
 | 
						|
        UsbIo,
 | 
						|
        StatusChangePort,
 | 
						|
        EfiUsbPortEnable
 | 
						|
        );
 | 
						|
 | 
						|
      gBS->Stall (50 * 1000);
 | 
						|
 | 
						|
      //
 | 
						|
      // Wait for bit change
 | 
						|
      //
 | 
						|
      Number = 10;
 | 
						|
      do {
 | 
						|
        HubGetPortStatus (
 | 
						|
          UsbIo,
 | 
						|
          StatusChangePort,
 | 
						|
          (UINT32 *) &HubPortStatus
 | 
						|
          );
 | 
						|
        gBS->Stall (10 * 1000);
 | 
						|
        Number -= 1;
 | 
						|
      } while ((HubPortStatus.PortStatus & USB_PORT_STAT_ENABLE) == 1 && Number > 0);
 | 
						|
 | 
						|
      if (Number == 0) {
 | 
						|
        //
 | 
						|
        // Cannot disable port, return error
 | 
						|
        //
 | 
						|
        DEBUG ((gUSBErrorLevel, "Disable Port Failed\n"));
 | 
						|
        gBS->FreePool (NewDevice);
 | 
						|
        return ;
 | 
						|
      }
 | 
						|
 | 
						|
      HubSetPortFeature (
 | 
						|
        UsbIo,
 | 
						|
        StatusChangePort,
 | 
						|
        EfiUsbPortReset
 | 
						|
        );
 | 
						|
 | 
						|
      gBS->Stall (50 * 1000);
 | 
						|
 | 
						|
      //
 | 
						|
      // Wait for port reset complete
 | 
						|
      //
 | 
						|
      Number = 10;
 | 
						|
      do {
 | 
						|
        HubGetPortStatus (
 | 
						|
          UsbIo,
 | 
						|
          StatusChangePort,
 | 
						|
          (UINT32 *) &HubPortStatus
 | 
						|
          );
 | 
						|
        gBS->Stall (10 * 1000);
 | 
						|
        Number -= 1;
 | 
						|
      } while ((HubPortStatus.PortStatus & USB_PORT_STAT_RESET) == 1 && Number > 0);
 | 
						|
 | 
						|
      if (Number == 0) {
 | 
						|
        //
 | 
						|
        // Cannot reset port, return error
 | 
						|
        //
 | 
						|
        DEBUG ((gUSBErrorLevel, "Reset Port Failed\n"));
 | 
						|
        gBS->FreePool (NewDevice);
 | 
						|
        return ;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Check high speed or full speed device
 | 
						|
      //
 | 
						|
      if (HubPortStatus.PortStatus & USB_PORT_STAT_LOW_SPEED) {
 | 
						|
        DEBUG ((gUSBDebugLevel, "Low Speed Device Attached to Hub\n"));
 | 
						|
        NewDevice->DeviceSpeed = EFI_USB_SPEED_LOW;
 | 
						|
      } else if (HubPortStatus.PortStatus & USB_PORT_STAT_HIGH_SPEED) {
 | 
						|
        DEBUG ((gUSBDebugLevel, "High Speed Device Attached to Hub\n"));
 | 
						|
        NewDevice->DeviceSpeed = EFI_USB_SPEED_HIGH;
 | 
						|
      } else {
 | 
						|
        DEBUG ((gUSBDebugLevel, "Full Speed Device Attached to Hub\n"));
 | 
						|
        NewDevice->DeviceSpeed = EFI_USB_SPEED_FULL;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Configure that device
 | 
						|
      //
 | 
						|
      Status = UsbDeviceConfiguration (
 | 
						|
                HubController,
 | 
						|
                HostController,
 | 
						|
                (UINT8) (StatusChangePort - 1),
 | 
						|
                NewDevice
 | 
						|
                );
 | 
						|
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        gBS->FreePool (NewDevice);
 | 
						|
        return ;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Add this device to the usb bus tree
 | 
						|
      // StatusChangePort is begin from 1,
 | 
						|
      //
 | 
						|
      HubController->Children[StatusChangePort - 1] = NewDevice;
 | 
						|
 | 
						|
      for (Index2 = 0; Index2 < NewDevice->NumOfControllers; Index2++) {
 | 
						|
        //
 | 
						|
        // If this device is hub, add to the hub index
 | 
						|
        //
 | 
						|
        NewController = NewDevice->UsbController[Index2];
 | 
						|
 | 
						|
        //
 | 
						|
        // Connect the controller to the driver image
 | 
						|
        //
 | 
						|
        Status = gBS->ConnectController (
 | 
						|
                        NewController->Handle,
 | 
						|
                        NULL,
 | 
						|
                        NULL,
 | 
						|
                        TRUE
 | 
						|
                        );
 | 
						|
        //
 | 
						|
        // If connect success, we need to disconnect when
 | 
						|
        // stop the controller, otherwise we need not call
 | 
						|
        // gBS->DisconnectController ()
 | 
						|
        // This is used by those usb devices we don't plan
 | 
						|
        // to support. We can allocate
 | 
						|
        // controller handles for them, but we don't have
 | 
						|
        // device drivers to manage them.
 | 
						|
        //
 | 
						|
        NewController->IsManagedByDriver = (BOOLEAN) (!EFI_ERROR (Status));
 | 
						|
 | 
						|
        //
 | 
						|
        // If this device is hub, add to the hub index
 | 
						|
        //
 | 
						|
        if (IsHub (NewController)) {
 | 
						|
 | 
						|
          NewController->IsUsbHub = TRUE;
 | 
						|
 | 
						|
          //
 | 
						|
          // Configure Hub
 | 
						|
          //
 | 
						|
          Status = DoHubConfig (NewController);
 | 
						|
 | 
						|
          if (EFI_ERROR (Status)) {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
          //
 | 
						|
          // Create an event to do hub enumeration
 | 
						|
          //
 | 
						|
          gBS->CreateEvent (
 | 
						|
                EFI_EVENT_NOTIFY_SIGNAL,
 | 
						|
                EFI_TPL_CALLBACK,
 | 
						|
                HubEnumeration,
 | 
						|
                NewController,
 | 
						|
                &NewController->HubNotify
 | 
						|
                );
 | 
						|
 | 
						|
          //
 | 
						|
          // Add request to do query hub status
 | 
						|
          // change endpoint
 | 
						|
          //
 | 
						|
          UsbIo = &NewController->UsbIo;
 | 
						|
          UsbIo->UsbAsyncInterruptTransfer (
 | 
						|
                  UsbIo,
 | 
						|
                  NewController->HubEndpointAddress,  // Hub endpoint address
 | 
						|
                  TRUE,
 | 
						|
                  100,
 | 
						|
                  1,                                  // Hub ports < 7
 | 
						|
                  OnHubInterruptComplete,
 | 
						|
                  NewController
 | 
						|
                  );
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Something disconnected from USB hub
 | 
						|
      //
 | 
						|
      DEBUG ((gUSBDebugLevel, "Something Device Detached on Hub port\n"));
 | 
						|
 | 
						|
      OldUsbIoDevice = HubController->Children[StatusChangePort - 1];
 | 
						|
 | 
						|
      UsbDeviceDeConfiguration (OldUsbIoDevice);
 | 
						|
 | 
						|
      HubController->Children[StatusChangePort - 1] = NULL;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
USB_IO_CONTROLLER_DEVICE *
 | 
						|
CreateUsbIoControllerDevice (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Allocate a structure for USB_IO_CONTROLLER_DEVICE
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    N/A
 | 
						|
 | 
						|
  Returns:
 | 
						|
    A pointer to a USB_IO_CONTROLLER_DEVICE structure,
 | 
						|
    Or NULL.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *UsbIoControllerDev;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate USB_IO_CONTROLLER_DEVICE structure
 | 
						|
  //
 | 
						|
  UsbIoControllerDev  = NULL;
 | 
						|
  UsbIoControllerDev  = AllocateZeroPool (sizeof (USB_IO_CONTROLLER_DEVICE));
 | 
						|
 | 
						|
  if (UsbIoControllerDev == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbIoControllerDev->Signature = USB_IO_CONTROLLER_SIGNATURE;
 | 
						|
 | 
						|
  return UsbIoControllerDev;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
InitUsbIoController (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE     *UsbIoController
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Init and install EFI_USB_IO_PROTOCOL onto that controller.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    UsbIoController   -   The Controller to be operated.
 | 
						|
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS
 | 
						|
    Others
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_DEVICE_PATH           UsbNode;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
 | 
						|
  EFI_USB_HC_PROTOCOL       *UsbHcProtocol;
 | 
						|
  EFI_USB2_HC_PROTOCOL      *Usb2HcProtocol;
 | 
						|
 | 
						|
  //
 | 
						|
  // Build the child device path for each new USB_IO device
 | 
						|
  //
 | 
						|
  ZeroMem (&UsbNode, sizeof (UsbNode));
 | 
						|
  UsbNode.Header.Type     = MESSAGING_DEVICE_PATH;
 | 
						|
  UsbNode.Header.SubType  = MSG_USB_DP;
 | 
						|
  SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode));
 | 
						|
  UsbNode.InterfaceNumber     = UsbIoController->InterfaceNumber;
 | 
						|
  UsbNode.ParentPortNumber    = UsbIoController->ParentPort;
 | 
						|
  ParentDevicePath            = UsbIoController->Parent->DevicePath;
 | 
						|
 | 
						|
  UsbIoController->DevicePath =
 | 
						|
  AppendDevicePathNode (ParentDevicePath, &UsbNode.Header);
 | 
						|
  if (UsbIoController->DevicePath == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  &UsbIoController->Handle,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  UsbIoController->DevicePath,
 | 
						|
                  &gEfiUsbIoProtocolGuid,
 | 
						|
                  &UsbIoController->UsbIo,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (UsbIoController->UsbDevice->BusController->Hc2ProtocolSupported) {
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    UsbIoController->HostController,
 | 
						|
                    &gEfiUsb2HcProtocolGuid,
 | 
						|
                    (VOID **)&Usb2HcProtocol,
 | 
						|
                    gUsbBusDriverBinding.DriverBindingHandle,
 | 
						|
                    UsbIoController->Handle,
 | 
						|
                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | 
						|
                    );
 | 
						|
  } else {
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    UsbIoController->HostController,
 | 
						|
                    &gEfiUsbHcProtocolGuid,
 | 
						|
                    (VOID **)&UsbHcProtocol,
 | 
						|
                    gUsbBusDriverBinding.DriverBindingHandle,
 | 
						|
                    UsbIoController->Handle,
 | 
						|
                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | 
						|
                    );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
ParentPortReset (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE    *UsbIoController,
 | 
						|
  IN BOOLEAN                     ReConfigure,
 | 
						|
  IN UINT8                       RetryTimes
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Reset parent hub port to which this device is connected.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    UsbIoController   - Indicating the Usb Controller Device.
 | 
						|
    ReConfigure       - Do we need to reconfigure it.
 | 
						|
    RetryTimes        - Retry Times when failed
 | 
						|
    
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_IO_DEVICE             *ParentIoDev;
 | 
						|
  USB_IO_DEVICE             *UsbIoDev;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *ParentController;
 | 
						|
  UINT8                     HubPort;
 | 
						|
  UINT32                    Status;
 | 
						|
  EFI_STATUS                Result;
 | 
						|
  EFI_USB_IO_PROTOCOL       *UsbIo;
 | 
						|
  UINT8                     Address;
 | 
						|
 | 
						|
  ParentController  = UsbIoController->Parent;
 | 
						|
  ParentIoDev       = ParentController->UsbDevice;
 | 
						|
  UsbIoDev          = UsbIoController->UsbDevice;
 | 
						|
  HubPort           = UsbIoController->ParentPort;
 | 
						|
 | 
						|
  gBS->Stall (100 * 1000);
 | 
						|
 | 
						|
  if (ParentIoDev->DeviceAddress == 1) {
 | 
						|
    DEBUG ((gUSBDebugLevel, "Reset from Root Hub 0x%x\n", HubPort));
 | 
						|
    ResetRootPort (ParentIoDev->BusController, HubPort, RetryTimes);
 | 
						|
  } else {
 | 
						|
    DEBUG ((gUSBDebugLevel, "Reset from Hub, Addr 0x%x\n", ParentIoDev->DeviceAddress));
 | 
						|
    ResetHubPort (ParentController, HubPort + 1);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If we only need port reset, just return
 | 
						|
  //
 | 
						|
  if (!ReConfigure) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Re-config that USB device
 | 
						|
  //
 | 
						|
  UsbIo = &UsbIoController->UsbIo;
 | 
						|
 | 
						|
  //
 | 
						|
  // Assign a unique address to this device
 | 
						|
  //
 | 
						|
  Address                 = UsbIoDev->DeviceAddress;
 | 
						|
  UsbIoDev->DeviceAddress = 0;
 | 
						|
 | 
						|
  Result                  = UsbSetDeviceAddress (UsbIo, Address, &Status);
 | 
						|
  UsbIoDev->DeviceAddress = Address;
 | 
						|
 | 
						|
  if (EFI_ERROR (Result)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Set the device to the default configuration
 | 
						|
  //
 | 
						|
  Result = UsbSetDefaultConfiguration (UsbIoDev);
 | 
						|
  if (EFI_ERROR (Result)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbPortReset (
 | 
						|
  IN EFI_USB_IO_PROTOCOL      *This
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Resets and reconfigures the USB controller.  This function will
 | 
						|
    work for all USB devices except USB Hub Controllers.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    This          -   Indicates the calling context.
 | 
						|
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS
 | 
						|
    EFI_INVALID_PARAMETER
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *UsbIoController;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This);
 | 
						|
 | 
						|
  //
 | 
						|
  // Since at this time, this device has already been configured,
 | 
						|
  // it needs to be re-configured.
 | 
						|
  //
 | 
						|
  Status = ParentPortReset (UsbIoController, TRUE, 0);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
ResetRootPort (
 | 
						|
  IN USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  IN UINT8                     PortNum,
 | 
						|
  IN UINT8                     RetryTimes
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Reset Root Hub port.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    UsbBusDev       - Bus controller of the device.
 | 
						|
    PortNum         - The given port to be reset.
 | 
						|
    RetryTimes      - RetryTimes when failed
 | 
						|
    
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  EFI_USB_PORT_STATUS PortStatus;
 | 
						|
 | 
						|
  //
 | 
						|
  // reset root port
 | 
						|
  //
 | 
						|
  Status = UsbVirtualHcSetRootHubPortFeature (
 | 
						|
            UsbBusDev,
 | 
						|
            PortNum,
 | 
						|
            EfiUsbPortReset
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->Stall (50 * 1000);
 | 
						|
 | 
						|
  //
 | 
						|
  // clear reset root port
 | 
						|
  //
 | 
						|
  Status = UsbVirtualHcClearRootHubPortFeature (
 | 
						|
            UsbBusDev,
 | 
						|
            PortNum,
 | 
						|
            EfiUsbPortReset
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->Stall (1000);
 | 
						|
 | 
						|
  Status = UsbVirtualHcClearRootHubPortFeature (
 | 
						|
            UsbBusDev,
 | 
						|
            PortNum,
 | 
						|
            EfiUsbPortConnectChange
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  UsbVirtualHcGetRootHubPortStatus (
 | 
						|
    UsbBusDev,
 | 
						|
    PortNum,
 | 
						|
    &PortStatus
 | 
						|
    );
 | 
						|
  if (PortStatus.PortStatus & USB_PORT_STAT_OWNER) {
 | 
						|
    //
 | 
						|
    // Set port enable
 | 
						|
    //
 | 
						|
    Status = UsbVirtualHcSetRootHubPortFeature (
 | 
						|
              UsbBusDev,
 | 
						|
              PortNum,
 | 
						|
              EfiUsbPortEnable
 | 
						|
              );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = UsbVirtualHcClearRootHubPortFeature (
 | 
						|
              UsbBusDev,
 | 
						|
              PortNum,
 | 
						|
              EfiUsbPortEnableChange
 | 
						|
              );
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->Stall ((1 + RetryTimes) * 50 * 1000);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
ResetHubPort (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE    *UsbIoController,
 | 
						|
  IN UINT8                       PortIndex
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Reset Hub port.
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    UsbIoController  -   The USB_IO_CONTROLLER_DEVICE instance.
 | 
						|
    PortIndex        -   The given port to be reset.
 | 
						|
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_USB_IO_PROTOCOL *UsbIo;
 | 
						|
  EFI_USB_PORT_STATUS HubPortStatus;
 | 
						|
  UINT8               Number;
 | 
						|
 | 
						|
  ASSERT (UsbIoController->IsUsbHub == TRUE);
 | 
						|
 | 
						|
  UsbIo = &UsbIoController->UsbIo;
 | 
						|
 | 
						|
  HubSetPortFeature (
 | 
						|
    UsbIo,
 | 
						|
    PortIndex,
 | 
						|
    EfiUsbPortReset
 | 
						|
    );
 | 
						|
 | 
						|
  gBS->Stall (10 * 1000);
 | 
						|
 | 
						|
  //
 | 
						|
  // Wait for port reset complete
 | 
						|
  //
 | 
						|
  Number = 10;
 | 
						|
  do {
 | 
						|
    HubGetPortStatus (
 | 
						|
      UsbIo,
 | 
						|
      PortIndex,
 | 
						|
      (UINT32 *) &HubPortStatus
 | 
						|
      );
 | 
						|
    gBS->Stall (10 * 100);
 | 
						|
    Number -= 1;
 | 
						|
  } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Number > 0);
 | 
						|
 | 
						|
  if (Number == 0) {
 | 
						|
    //
 | 
						|
    // Cannot reset port, return error
 | 
						|
    //
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->Stall (1000);
 | 
						|
 | 
						|
  HubGetPortStatus (
 | 
						|
    UsbIo,
 | 
						|
    PortIndex,
 | 
						|
    (UINT32 *) &HubPortStatus
 | 
						|
    );
 | 
						|
  //
 | 
						|
  // reset port will cause some bits change, clear them
 | 
						|
  //
 | 
						|
  if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_ENABLE) {
 | 
						|
    DEBUG ((gUSBDebugLevel, "Port Enable Change\n"));
 | 
						|
    HubClearPortFeature (
 | 
						|
      UsbIo,
 | 
						|
      PortIndex,
 | 
						|
      EfiUsbPortEnableChange
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) {
 | 
						|
    DEBUG ((gUSBDebugLevel, "Port Reset Change\n"));
 | 
						|
    HubClearPortFeature (
 | 
						|
      UsbIo,
 | 
						|
      PortIndex,
 | 
						|
      EfiUsbPortResetChange
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
ReportUsbStatusCode (
 | 
						|
  IN USB_BUS_CONTROLLER_DEVICE     *UsbBusController,
 | 
						|
  IN EFI_STATUS_CODE_TYPE          Type,
 | 
						|
  IN EFI_STATUS_CODE_VALUE         Code
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  report a error Status code of USB bus driver controller
 | 
						|
 | 
						|
 Arguments:
 | 
						|
   UsbBusController - USB_BUS_CONTROLLER_DEVICE
 | 
						|
   Type             - EFI_STATUS_CODE_TYPE
 | 
						|
   Code             - EFI_STATUS_CODE_VALUE
 | 
						|
 Returns:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | 
						|
          Type,
 | 
						|
          Code,
 | 
						|
          UsbBusController->DevicePath
 | 
						|
          );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
IsDeviceDisconnected (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE    *UsbIoController,
 | 
						|
  IN OUT BOOLEAN                 *Disconnected
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
  Routine Description:
 | 
						|
    Reset if the device is disconencted or not
 | 
						|
 | 
						|
  Arguments:
 | 
						|
    UsbIoController   -   Indicating the Usb Controller Device.
 | 
						|
    Disconnected      -   Indicate whether the device is disconencted or not
 | 
						|
 | 
						|
  Returns:
 | 
						|
    EFI_SUCCESS
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_IO_DEVICE             *ParentIoDev;
 | 
						|
  USB_IO_DEVICE             *UsbIoDev;
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *ParentController;
 | 
						|
  UINT8                     HubPort;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_USB_IO_PROTOCOL       *UsbIo;
 | 
						|
  EFI_USB_PORT_STATUS       PortStatus;
 | 
						|
 | 
						|
  ParentController  = UsbIoController->Parent;
 | 
						|
  ParentIoDev       = ParentController->UsbDevice;
 | 
						|
  UsbIoDev          = UsbIoController->UsbDevice;
 | 
						|
  HubPort           = UsbIoController->ParentPort;
 | 
						|
 | 
						|
  if (ParentIoDev->DeviceAddress == 1) {
 | 
						|
    //
 | 
						|
    // Connected to the root hub
 | 
						|
    //
 | 
						|
    UsbVirtualHcGetRootHubPortStatus (
 | 
						|
      ParentIoDev->BusController,
 | 
						|
      HubPort,
 | 
						|
      &PortStatus
 | 
						|
      );
 | 
						|
 | 
						|
  } else {
 | 
						|
    UsbIo = &UsbIoController->UsbIo;
 | 
						|
    Status = HubGetPortStatus (
 | 
						|
              &ParentController->UsbIo,
 | 
						|
              HubPort + 1,
 | 
						|
              (UINT32 *) &PortStatus
 | 
						|
              );
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return IsDeviceDisconnected (ParentController, Disconnected);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  *Disconnected = FALSE;
 | 
						|
 | 
						|
  if (!IsPortConnect (PortStatus.PortStatus)) {
 | 
						|
    *Disconnected = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
UsbSetTransactionTranslator (
 | 
						|
  IN USB_IO_CONTROLLER_DEVICE     *ParentHubController,
 | 
						|
  IN UINT8                        ParentPort,
 | 
						|
  IN OUT USB_IO_DEVICE            *Device
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Set Transaction Translator parameter
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
  
 | 
						|
    ParentHubController  - Controller structure of the parent Hub device
 | 
						|
    ParentPort           - Number of parent port
 | 
						|
    Device               - Structure of the device
 | 
						|
    
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS            Success
 | 
						|
    EFI_OUT_OF_RESOURCES   Cannot allocate resources
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  USB_IO_CONTROLLER_DEVICE  *AncestorHubController;
 | 
						|
 | 
						|
  AncestorHubController = ParentHubController;
 | 
						|
  Device->Translator    = NULL;
 | 
						|
 | 
						|
  if (EFI_USB_SPEED_HIGH == Device->DeviceSpeed) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  do {
 | 
						|
    if (EFI_USB_SPEED_HIGH == AncestorHubController->UsbDevice->DeviceSpeed) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    if (NULL == AncestorHubController->Parent) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    AncestorHubController = AncestorHubController->Parent;
 | 
						|
  } while (1);
 | 
						|
 | 
						|
  Device->Translator = AllocatePool (sizeof (EFI_USB2_HC_TRANSACTION_TRANSLATOR));
 | 
						|
  if (NULL == Device->Translator) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Device->Translator->TranslatorHubAddress  = AncestorHubController->UsbDevice->DeviceAddress;
 | 
						|
  Device->Translator->TranslatorPortNumber  = ParentPort;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
UsbUnsetTransactionTranslator (
 | 
						|
  USB_IO_DEVICE *Device
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Unset Transaction Translator parameter
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    Device - Structure of the device
 | 
						|
    
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS    Success
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  if (Device->Translator) {
 | 
						|
    gBS->FreePool (Device->Translator);
 | 
						|
    Device->Translator = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
IdentifyDeviceSpeed (
 | 
						|
  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  USB_IO_DEVICE             *NewDevice,
 | 
						|
  UINT8                     Index
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Identify speed of USB device
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    UsbBusDev  - UsbBus controller structure of the device
 | 
						|
    NewDevice  - Devcie controller structure
 | 
						|
    Index      - Number of the port
 | 
						|
    
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS        Success
 | 
						|
    EFI_NOT_FOUND      Device release to CHC or can't be found
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS             Status;
 | 
						|
  EFI_USB_PORT_STATUS    HubPortStatus;
 | 
						|
 | 
						|
  UsbVirtualHcGetRootHubPortStatus (
 | 
						|
    UsbBusDev,
 | 
						|
    Index,
 | 
						|
    (EFI_USB_PORT_STATUS *) &HubPortStatus
 | 
						|
    );
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Check device device
 | 
						|
  //
 | 
						|
  if (!(HubPortStatus.PortStatus & USB_PORT_STAT_OWNER)) {
 | 
						|
    //
 | 
						|
    // EHC Port Owner
 | 
						|
    //
 | 
						|
    if (HubPortStatus.PortStatus & USB_PORT_STAT_HIGH_SPEED) {
 | 
						|
      DEBUG ((gUSBDebugLevel, "High Speed Device attached to EHC\n"));
 | 
						|
      NewDevice->DeviceSpeed = EFI_USB_SPEED_HIGH; 
 | 
						|
    } else {
 | 
						|
      Status = ReleasePortToCHC (UsbBusDev, Index);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        DEBUG ((gUSBErrorLevel, "Fail to release port to CHC\n"));
 | 
						|
      } else {
 | 
						|
        DEBUG ((gUSBDebugLevel, "Success to release port to CHC\n"));
 | 
						|
      }
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // CHC Port Owner
 | 
						|
    //
 | 
						|
    if (HubPortStatus.PortStatus & USB_PORT_STAT_LOW_SPEED) {
 | 
						|
      DEBUG ((gUSBDebugLevel, "Low Speed Device attached to CHC\n"));
 | 
						|
      NewDevice->DeviceSpeed = EFI_USB_SPEED_LOW; 
 | 
						|
    } else {
 | 
						|
      DEBUG ((gUSBDebugLevel, "FULL Speed Device attached to CHC\n"));
 | 
						|
      NewDevice->DeviceSpeed = EFI_USB_SPEED_FULL; 
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
ReleasePortToCHC (
 | 
						|
  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  UINT8                     PortNum
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Set bit to release the port owner to CHC
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    UsbBusDev  - UsbBus controller structure of the device
 | 
						|
    PortNum    - Number of the port
 | 
						|
    
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS        Success
 | 
						|
    EFI_DEVICE_ERROR   Fail
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = UsbVirtualHcSetRootHubPortFeature (
 | 
						|
            UsbBusDev,
 | 
						|
            PortNum,
 | 
						|
            EfiUsbPortOwner
 | 
						|
            );
 | 
						|
 | 
						|
  gBS->Stall (100 * 1000);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcGetCapability (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  OUT UINT8                     *MaxSpeed,
 | 
						|
  OUT UINT8                     *PortNumber,
 | 
						|
  OUT UINT8                     *Is64BitCapable
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to Retrieves the capablility of root hub ports 
 | 
						|
    for both Hc2 and Hc protocol.
 | 
						|
    
 | 
						|
  Arguments:
 | 
						|
  
 | 
						|
    UsbBusDev       - A pointer to bus controller of the device.
 | 
						|
    MaxSpeed        - A pointer to the number of the host controller.
 | 
						|
    PortNumber      - A pointer to the number of the root hub ports.
 | 
						|
    Is64BitCapable  - A pointer to the flag for whether controller supports 
 | 
						|
                      64-bit memory addressing.
 | 
						|
    
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
          The host controller capability were retrieved successfully.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
          MaxSpeed or PortNumber or Is64BitCapable is NULL.
 | 
						|
    EFI_DEVICE_ERROR  
 | 
						|
          An error was encountered while attempting to retrieve the capabilities.  
 | 
						|
          
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->GetCapability (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          MaxSpeed,
 | 
						|
                                          PortNumber,
 | 
						|
                                          Is64BitCapable
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    Status = UsbBusDev->UsbHCInterface->GetRootHubPortNumber (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          PortNumber
 | 
						|
                                          );
 | 
						|
    *MaxSpeed       = EFI_USB_SPEED_FULL;
 | 
						|
    *Is64BitCapable = (UINT8) FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcReset (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  IN UINT16                     Attributes
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to provides software reset for the USB host controller
 | 
						|
    for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
  
 | 
						|
    UsbBusDev   - A pointer to bus controller of the device.
 | 
						|
    Attributes  - A bit mask of the reset operation to perform. 
 | 
						|
                See below for a list of the supported bit mask values.
 | 
						|
  
 | 
						|
  #define EFI_USB_HC_RESET_GLOBAL  0x0001               // Hc2 and Hc
 | 
						|
  #define EFI_USB_HC_RESET_HOST_CONTROLLER  0x0002      // Hc2 and Hc
 | 
						|
  #define EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG  0x0004    // Hc2
 | 
						|
  #define EFI_USB_HC_RESET_HOST_WITH_DEBUG  0x0008      // Hc2
 | 
						|
 | 
						|
  EFI_USB_HC_RESET_GLOBAL 
 | 
						|
        If this bit is set, a global reset signal will be sent to the USB bus.
 | 
						|
        This resets all of the USB bus logic, including the USB host 
 | 
						|
        controller hardware and all the devices attached on the USB bus.
 | 
						|
  EFI_USB_HC_RESET_HOST_CONTROLLER  
 | 
						|
        If this bit is set, the USB host controller hardware will be reset. 
 | 
						|
        No reset signal will be sent to the USB bus.
 | 
						|
  EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG
 | 
						|
        If this bit is set, a global reset signal will be sent to the USB bus.
 | 
						|
        This resets all of the USB bus logic, including the USB host 
 | 
						|
        controller hardware and all the devices attached on the USB bus. 
 | 
						|
        If this is an EHCI controller and the debug port has configured, then 
 | 
						|
        this is will still reset the host controller.
 | 
						|
  EFI_USB_HC_RESET_HOST_WITH_DEBUG
 | 
						|
        If this bit is set, the USB host controller hardware will be reset. 
 | 
						|
        If this is an EHCI controller and the debug port has been configured,
 | 
						|
        then this will still reset the host controller.
 | 
						|
        
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
        The reset operation succeeded.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
        Attributes is not valid.
 | 
						|
    EFI_UNSUPPOURTED
 | 
						|
        The type of reset specified by Attributes is not currently supported by
 | 
						|
        the host controller hardware.
 | 
						|
    EFI_ACCESS_DENIED
 | 
						|
        Reset operation is rejected due to the debug port being configured and 
 | 
						|
        active; only EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG or 
 | 
						|
        EFI_USB_HC_RESET_HOST_WITH_DEBUG reset Atrributes can be used to
 | 
						|
        perform reset operation for this host controller.
 | 
						|
    EFI_DEVICE_ERROR  
 | 
						|
        An error was encountered while attempting to perform 
 | 
						|
        the reset operation.
 | 
						|
        
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->Reset (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          EFI_USB_HC_RESET_GLOBAL
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    Status = UsbBusDev->UsbHCInterface->Reset (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          EFI_USB_HC_RESET_GLOBAL
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcGetState (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  OUT EFI_USB_HC_STATE          *State
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to retrieves current state of the USB host controller
 | 
						|
    for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    UsbBusDev - A pointer to bus controller of the device.
 | 
						|
    State     - A pointer to the EFI_USB_HC_STATE data structure that 
 | 
						|
              indicates current state of the USB host controller.  
 | 
						|
              Type EFI_USB_HC_STATE is defined below.
 | 
						|
              
 | 
						|
    typedef enum {
 | 
						|
      EfiUsbHcStateHalt,
 | 
						|
      EfiUsbHcStateOperational,
 | 
						|
      EfiUsbHcStateSuspend,
 | 
						|
      EfiUsbHcStateMaximum
 | 
						|
    } EFI_USB_HC_STATE;
 | 
						|
  
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
            The state information of the host controller was returned in State.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
            State is NULL.
 | 
						|
    EFI_DEVICE_ERROR  
 | 
						|
            An error was encountered while attempting to retrieve the 
 | 
						|
            host controller's current state.  
 | 
						|
            
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->GetState (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          State
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    Status = UsbBusDev->UsbHCInterface->GetState (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          State
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcSetState (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  IN EFI_USB_HC_STATE           State
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to sets the USB host controller to a specific state
 | 
						|
    for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    UsbBusDev   - A pointer to bus controller of the device.
 | 
						|
    State       - Indicates the state of the host controller that will be set.
 | 
						|
  
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
          The USB host controller was successfully placed in the state 
 | 
						|
          specified by State.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
          State is invalid.
 | 
						|
    EFI_DEVICE_ERROR  
 | 
						|
          Failed to set the state specified by State due to device error.  
 | 
						|
          
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->SetState (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          State
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    Status = UsbBusDev->UsbHCInterface->SetState (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          State
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcGetRootHubPortStatus (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  IN  UINT8                     PortNumber,
 | 
						|
  OUT EFI_USB_PORT_STATUS       *PortStatus
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to retrieves the current status of a USB root hub port
 | 
						|
    both for Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
  
 | 
						|
    UsbBusDev   - A pointer to bus controller of the device.
 | 
						|
    PortNumber  - Specifies the root hub port from which the status 
 | 
						|
                is to be retrieved.  This value is zero-based. For example, 
 | 
						|
                if a root hub has two ports, then the first port is numbered 0,
 | 
						|
                and the second port is numbered 1.
 | 
						|
    PortStatus  - A pointer to the current port status bits and 
 | 
						|
                port status change bits.  
 | 
						|
  
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS  The status of the USB root hub port specified by PortNumber 
 | 
						|
                 was returned in PortStatus.
 | 
						|
    EFI_INVALID_PARAMETER PortNumber is invalid. 
 | 
						|
    EFI_DEVICE_ERROR      Can't read register     
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->GetRootHubPortStatus (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          PortNumber,
 | 
						|
                                          PortStatus
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    Status = UsbBusDev->UsbHCInterface->GetRootHubPortStatus (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          PortNumber,
 | 
						|
                                          PortStatus
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcSetRootHubPortFeature (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  IN  UINT8                     PortNumber,
 | 
						|
  IN  EFI_USB_PORT_FEATURE      PortFeature
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
    Virual interface to sets a feature for the specified root hub port
 | 
						|
    for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
  
 | 
						|
    UsbBusDev   - A pointer to bus controller of the device.
 | 
						|
    PortNumber  - Specifies the root hub port whose feature 
 | 
						|
                is requested to be set.
 | 
						|
    PortFeature - Indicates the feature selector associated 
 | 
						|
                with the feature set request. 
 | 
						|
  
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
        The feature specified by PortFeature was set for the 
 | 
						|
        USB root hub port specified by PortNumber.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
        PortNumber is invalid or PortFeature is invalid.
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
        Can't read register
 | 
						|
        
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->SetRootHubPortFeature (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          PortNumber,
 | 
						|
                                          PortFeature
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    Status = UsbBusDev->UsbHCInterface->SetRootHubPortFeature (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          PortNumber,
 | 
						|
                                          PortFeature
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcClearRootHubPortFeature (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE *UsbBusDev,
 | 
						|
  IN  UINT8                     PortNumber,
 | 
						|
  IN  EFI_USB_PORT_FEATURE      PortFeature
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to clears a feature for the specified root hub port
 | 
						|
    for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
  
 | 
						|
    UsbBusDev   - A pointer to bus controller of the device.
 | 
						|
    PortNumber  - Specifies the root hub port whose feature 
 | 
						|
                is requested to be cleared.
 | 
						|
    PortFeature - Indicates the feature selector associated with the 
 | 
						|
                feature clear request.
 | 
						|
                  
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
        The feature specified by PortFeature was cleared for the 
 | 
						|
        USB root hub port specified by PortNumber.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
        PortNumber is invalid or PortFeature is invalid.
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
        Can't read register
 | 
						|
        
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->ClearRootHubPortFeature (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          PortNumber,
 | 
						|
                                          PortFeature
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    Status = UsbBusDev->UsbHCInterface->ClearRootHubPortFeature (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          PortNumber,
 | 
						|
                                          PortFeature
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcControlTransfer (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE            *UsbBusDev,
 | 
						|
  IN  UINT8                                DeviceAddress,
 | 
						|
  IN  UINT8                                DeviceSpeed,
 | 
						|
  IN  UINTN                                MaximumPacketLength,
 | 
						|
  IN  EFI_USB_DEVICE_REQUEST               *Request,
 | 
						|
  IN  EFI_USB_DATA_DIRECTION               TransferDirection,
 | 
						|
  IN  OUT VOID                             *Data,
 | 
						|
  IN  OUT UINTN                            *DataLength,
 | 
						|
  IN  UINTN                                TimeOut,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR   *Translator,
 | 
						|
  OUT UINT32                               *TransferResult
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to submits control transfer to a target USB device
 | 
						|
    for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    UsbBusDev     - A pointer to bus controller of the device.
 | 
						|
    DeviceAddress - Represents the address of the target device on the USB,
 | 
						|
                  which is assigned during USB enumeration.
 | 
						|
    DeviceSpeed   - Indicates target device speed.
 | 
						|
    MaximumPacketLength - Indicates the maximum packet size that the 
 | 
						|
                        default control transfer endpoint is capable of 
 | 
						|
                        sending or receiving.
 | 
						|
    Request       - A pointer to the USB device request that will be sent 
 | 
						|
                  to the USB device. 
 | 
						|
    TransferDirection - Specifies the data direction for the transfer.
 | 
						|
                      There are three values available, DataIn, DataOut 
 | 
						|
                      and NoData.
 | 
						|
    Data          - A pointer to the buffer of data that will be transmitted 
 | 
						|
                  to USB device or received from USB device.
 | 
						|
    DataLength    - Indicates the size, in bytes, of the data buffer 
 | 
						|
                  specified by Data.
 | 
						|
    TimeOut       - Indicates the maximum time, in microseconds, 
 | 
						|
                  which the transfer is allowed to complete.
 | 
						|
    Translator      - A pointr to the transaction translator data.
 | 
						|
    TransferResult  - A pointer to the detailed result information generated 
 | 
						|
                    by this control transfer.
 | 
						|
                    
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
        The control transfer was completed successfully.
 | 
						|
    EFI_OUT_OF_RESOURCES  
 | 
						|
        The control transfer could not be completed due to a lack of resources.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
        Some parameters are invalid.
 | 
						|
    EFI_TIMEOUT 
 | 
						|
        The control transfer failed due to timeout.
 | 
						|
    EFI_DEVICE_ERROR  
 | 
						|
        The control transfer failed due to host controller or device error. 
 | 
						|
        Caller should check TranferResult for detailed error information.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  BOOLEAN     IsSlowDevice;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->ControlTransfer (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          DeviceAddress,
 | 
						|
                                          DeviceSpeed,
 | 
						|
                                          MaximumPacketLength,
 | 
						|
                                          Request,
 | 
						|
                                          TransferDirection,
 | 
						|
                                          Data,
 | 
						|
                                          DataLength,
 | 
						|
                                          TimeOut,
 | 
						|
                                          Translator,
 | 
						|
                                          TransferResult
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    IsSlowDevice = (EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE;
 | 
						|
    Status = UsbBusDev->UsbHCInterface->ControlTransfer (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          DeviceAddress,
 | 
						|
                                          IsSlowDevice,
 | 
						|
                                          (UINT8) MaximumPacketLength,
 | 
						|
                                          Request,
 | 
						|
                                          TransferDirection,
 | 
						|
                                          Data,
 | 
						|
                                          DataLength,
 | 
						|
                                          TimeOut,
 | 
						|
                                          TransferResult
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcBulkTransfer (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE           *UsbBusDev,
 | 
						|
  IN  UINT8                               DeviceAddress,
 | 
						|
  IN  UINT8                               EndPointAddress,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINTN                               MaximumPacketLength,
 | 
						|
  IN  UINT8                               DataBuffersNumber,
 | 
						|
  IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
 | 
						|
  IN  OUT UINTN                           *DataLength,
 | 
						|
  IN  OUT UINT8                           *DataToggle,
 | 
						|
  IN  UINTN                               TimeOut,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  OUT UINT32                              *TransferResult
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to submits bulk transfer to a bulk endpoint of a USB device
 | 
						|
    both for Hc2 and Hc protocol.
 | 
						|
    
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    UsbBusDev         - A pointer to bus controller of the device.
 | 
						|
    DeviceAddress     - Represents the address of the target device on the USB,
 | 
						|
                      which is assigned during USB enumeration.               
 | 
						|
    EndPointAddress   - The combination of an endpoint number and an 
 | 
						|
                      endpoint direction of the target USB device. 
 | 
						|
                      Each endpoint address supports data transfer in 
 | 
						|
                      one direction except the control endpoint 
 | 
						|
                      (whose default endpoint address is 0). 
 | 
						|
                      It is the caller's responsibility to make sure that 
 | 
						|
                      the EndPointAddress represents a bulk endpoint.                  
 | 
						|
    DeviceSpeed       - Indicates device speed. The supported values are EFI_USB_SPEED_FULL
 | 
						|
                      and EFI_USB_SPEED_HIGH.
 | 
						|
    MaximumPacketLength - Indicates the maximum packet size the target endpoint
 | 
						|
                        is capable of sending or receiving.                 
 | 
						|
    DataBuffersNumber - Number of data buffers prepared for the transfer.
 | 
						|
    Data              - Array of pointers to the buffers of data that will be transmitted 
 | 
						|
                      to USB device or received from USB device.              
 | 
						|
    DataLength        - When input, indicates the size, in bytes, of the data buffer
 | 
						|
                      specified by Data. When output, indicates the actually 
 | 
						|
                      transferred data size.              
 | 
						|
    DataToggle        - A pointer to the data toggle value. On input, it indicates 
 | 
						|
                      the initial data toggle value the bulk transfer should adopt;
 | 
						|
                      on output, it is updated to indicate the data toggle value 
 | 
						|
                      of the subsequent bulk transfer. 
 | 
						|
    Translator        - A pointr to the transaction translator data. 
 | 
						|
    TimeOut           - Indicates the maximum time, in microseconds, which the 
 | 
						|
                      transfer is allowed to complete.              
 | 
						|
    TransferResult    - A pointer to the detailed result information of the 
 | 
						|
                      bulk transfer.
 | 
						|
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
        The bulk transfer was completed successfully.
 | 
						|
    EFI_OUT_OF_RESOURCES  
 | 
						|
        The bulk transfer could not be submitted due to lack of resource.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
        Some parameters are invalid.
 | 
						|
    EFI_TIMEOUT 
 | 
						|
        The bulk transfer failed due to timeout.
 | 
						|
    EFI_DEVICE_ERROR  
 | 
						|
        The bulk transfer failed due to host controller or device error.
 | 
						|
        Caller should check TranferResult for detailed error information.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->BulkTransfer (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          DeviceAddress,
 | 
						|
                                          EndPointAddress,
 | 
						|
                                          DeviceSpeed,
 | 
						|
                                          MaximumPacketLength,
 | 
						|
                                          DataBuffersNumber,
 | 
						|
                                          Data,
 | 
						|
                                          DataLength,
 | 
						|
                                          DataToggle,
 | 
						|
                                          TimeOut,
 | 
						|
                                          Translator,
 | 
						|
                                          TransferResult
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    Status = UsbBusDev->UsbHCInterface->BulkTransfer (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          DeviceAddress,
 | 
						|
                                          EndPointAddress,
 | 
						|
                                          (UINT8) MaximumPacketLength,
 | 
						|
                                          *Data,
 | 
						|
                                          DataLength,
 | 
						|
                                          DataToggle,
 | 
						|
                                          TimeOut,
 | 
						|
                                          TransferResult
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcAsyncInterruptTransfer (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE             * UsbBusDev,
 | 
						|
  IN  UINT8                                 DeviceAddress,
 | 
						|
  IN  UINT8                                 EndPointAddress,
 | 
						|
  IN  UINT8                                 DeviceSpeed,
 | 
						|
  IN  UINTN                                 MaximumPacketLength,
 | 
						|
  IN  BOOLEAN                               IsNewTransfer,
 | 
						|
  IN OUT UINT8                              *DataToggle,
 | 
						|
  IN  UINTN                                 PollingInterval,
 | 
						|
  IN  UINTN                                 DataLength,
 | 
						|
  IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,
 | 
						|
  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK       CallBackFunction,
 | 
						|
  IN  VOID                                  *Context OPTIONAL
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to submits an asynchronous interrupt transfer to an 
 | 
						|
    interrupt endpoint of a USB device for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    UsbBusDev       - A pointer to bus controller of the device.
 | 
						|
    DeviceAddress   - Represents the address of the target device on the USB,
 | 
						|
                    which is assigned during USB enumeration.                
 | 
						|
    EndPointAddress - The combination of an endpoint number and an endpoint 
 | 
						|
                    direction of the target USB device. Each endpoint address 
 | 
						|
                    supports data transfer in one direction except the 
 | 
						|
                    control endpoint (whose default endpoint address is 0). 
 | 
						|
                    It is the caller's responsibility to make sure that 
 | 
						|
                    the EndPointAddress represents an interrupt endpoint.              
 | 
						|
    DeviceSpeed     - Indicates device speed.
 | 
						|
    MaximumPacketLength  - Indicates the maximum packet size the target endpoint
 | 
						|
                         is capable of sending or receiving.                   
 | 
						|
    IsNewTransfer   - If TRUE, an asynchronous interrupt pipe is built between
 | 
						|
                    the host and the target interrupt endpoint. 
 | 
						|
                    If FALSE, the specified asynchronous interrupt pipe 
 | 
						|
                    is canceled.               
 | 
						|
    DataToggle      - A pointer to the data toggle value.  On input, it is valid 
 | 
						|
                    when IsNewTransfer is TRUE, and it indicates the initial 
 | 
						|
                    data toggle value the asynchronous interrupt transfer 
 | 
						|
                    should adopt.  
 | 
						|
                    On output, it is valid when IsNewTransfer is FALSE, 
 | 
						|
                    and it is updated to indicate the data toggle value of 
 | 
						|
                    the subsequent asynchronous interrupt transfer.              
 | 
						|
    PollingInterval - Indicates the interval, in milliseconds, that the 
 | 
						|
                    asynchronous interrupt transfer is polled.  
 | 
						|
                    This parameter is required when IsNewTransfer is TRUE.               
 | 
						|
    DataLength      - Indicates the length of data to be received at the 
 | 
						|
                    rate specified by PollingInterval from the target 
 | 
						|
                    asynchronous interrupt endpoint.  This parameter 
 | 
						|
                    is only required when IsNewTransfer is TRUE.             
 | 
						|
    Translator      - A pointr to the transaction translator data.
 | 
						|
    CallBackFunction  - The Callback function.This function is called at the 
 | 
						|
                      rate specified by PollingInterval.This parameter is 
 | 
						|
                      only required when IsNewTransfer is TRUE.               
 | 
						|
    Context         - The context that is passed to the CallBackFunction.
 | 
						|
                    - This is an optional parameter and may be NULL.
 | 
						|
  
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
        The asynchronous interrupt transfer request has been successfully 
 | 
						|
        submitted or canceled.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
        Some parameters are invalid.
 | 
						|
    EFI_OUT_OF_RESOURCES  
 | 
						|
        The request could not be completed due to a lack of resources.  
 | 
						|
    EFI_DEVICE_ERROR
 | 
						|
        Can't read register
 | 
						|
        
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  BOOLEAN     IsSlowDevice;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->AsyncInterruptTransfer (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          DeviceAddress,
 | 
						|
                                          EndPointAddress,
 | 
						|
                                          DeviceSpeed,
 | 
						|
                                          MaximumPacketLength,
 | 
						|
                                          IsNewTransfer,
 | 
						|
                                          DataToggle,
 | 
						|
                                          PollingInterval,
 | 
						|
                                          DataLength,
 | 
						|
                                          Translator,
 | 
						|
                                          CallBackFunction,
 | 
						|
                                          Context
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    IsSlowDevice = (EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE;
 | 
						|
    Status = UsbBusDev->UsbHCInterface->AsyncInterruptTransfer (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          DeviceAddress,
 | 
						|
                                          EndPointAddress,
 | 
						|
                                          IsSlowDevice,
 | 
						|
                                          (UINT8) MaximumPacketLength,
 | 
						|
                                          IsNewTransfer,
 | 
						|
                                          DataToggle,
 | 
						|
                                          PollingInterval,
 | 
						|
                                          DataLength,
 | 
						|
                                          CallBackFunction,
 | 
						|
                                          Context
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcSyncInterruptTransfer (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE             *UsbBusDev,
 | 
						|
  IN  UINT8                                 DeviceAddress,
 | 
						|
  IN  UINT8                                 EndPointAddress,
 | 
						|
  IN  UINT8                                 DeviceSpeed,
 | 
						|
  IN  UINTN                                 MaximumPacketLength,
 | 
						|
  IN OUT VOID                               *Data,
 | 
						|
  IN OUT UINTN                              *DataLength,
 | 
						|
  IN OUT UINT8                              *DataToggle,
 | 
						|
  IN  UINTN                                 TimeOut,
 | 
						|
  IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
 | 
						|
  OUT UINT32                                *TransferResult
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Vitual interface to submits synchronous interrupt transfer to an interrupt endpoint 
 | 
						|
    of a USB device for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    UsbBusDev       - A pointer to bus controller of the device.
 | 
						|
    DeviceAddress   - Represents the address of the target device on the USB, 
 | 
						|
                    which is assigned during USB enumeration.
 | 
						|
    EndPointAddress   - The combination of an endpoint number and an endpoint 
 | 
						|
                      direction of the target USB device. Each endpoint 
 | 
						|
                      address supports data transfer in one direction 
 | 
						|
                      except the control endpoint (whose default 
 | 
						|
                      endpoint address is 0). It is the caller's responsibility
 | 
						|
                      to make sure that the EndPointAddress represents 
 | 
						|
                      an interrupt endpoint. 
 | 
						|
    DeviceSpeed     - Indicates device speed.
 | 
						|
    MaximumPacketLength - Indicates the maximum packet size the target endpoint 
 | 
						|
                        is capable of sending or receiving.
 | 
						|
    Data            - A pointer to the buffer of data that will be transmitted 
 | 
						|
                    to USB device or received from USB device.
 | 
						|
    DataLength      - On input, the size, in bytes, of the data buffer specified 
 | 
						|
                    by Data. On output, the number of bytes transferred.
 | 
						|
    DataToggle      - A pointer to the data toggle value. On input, it indicates
 | 
						|
                    the initial data toggle value the synchronous interrupt 
 | 
						|
                    transfer should adopt; 
 | 
						|
                    on output, it is updated to indicate the data toggle value 
 | 
						|
                    of the subsequent synchronous interrupt transfer. 
 | 
						|
    TimeOut         - Indicates the maximum time, in microseconds, which the 
 | 
						|
                    transfer is allowed to complete.
 | 
						|
    Translator      - A pointr to the transaction translator data.
 | 
						|
    TransferResult  - A pointer to the detailed result information from 
 | 
						|
                    the synchronous interrupt transfer.  
 | 
						|
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_SUCCESS 
 | 
						|
        The synchronous interrupt transfer was completed successfully.
 | 
						|
    EFI_OUT_OF_RESOURCES  
 | 
						|
        The synchronous interrupt transfer could not be submitted due 
 | 
						|
        to lack of resource.
 | 
						|
    EFI_INVALID_PARAMETER 
 | 
						|
        Some parameters are invalid.
 | 
						|
    EFI_TIMEOUT 
 | 
						|
        The synchronous interrupt transfer failed due to timeout.
 | 
						|
    EFI_DEVICE_ERROR  
 | 
						|
        The synchronous interrupt transfer failed due to host controller 
 | 
						|
        or device error. Caller should check TranferResult for detailed 
 | 
						|
        error information.  
 | 
						|
        
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  BOOLEAN     IsSlowDevice;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (UsbBusDev->Hc2ProtocolSupported) {
 | 
						|
    Status = UsbBusDev->Usb2HCInterface->SyncInterruptTransfer (
 | 
						|
                                          UsbBusDev->Usb2HCInterface,
 | 
						|
                                          DeviceAddress,
 | 
						|
                                          EndPointAddress,
 | 
						|
                                          DeviceSpeed,
 | 
						|
                                          MaximumPacketLength,
 | 
						|
                                          Data,
 | 
						|
                                          DataLength,
 | 
						|
                                          DataToggle,
 | 
						|
                                          TimeOut,
 | 
						|
                                          Translator,
 | 
						|
                                          TransferResult
 | 
						|
                                          );
 | 
						|
  } else {
 | 
						|
    IsSlowDevice = (EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE;
 | 
						|
    Status = UsbBusDev->UsbHCInterface->SyncInterruptTransfer (
 | 
						|
                                          UsbBusDev->UsbHCInterface,
 | 
						|
                                          DeviceAddress,
 | 
						|
                                          EndPointAddress,
 | 
						|
                                          IsSlowDevice,
 | 
						|
                                          (UINT8) MaximumPacketLength,
 | 
						|
                                          Data,
 | 
						|
                                          DataLength,
 | 
						|
                                          DataToggle,
 | 
						|
                                          TimeOut,
 | 
						|
                                          TransferResult
 | 
						|
                                          );
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcIsochronousTransfer (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE             *UsbBusDev,
 | 
						|
  IN  UINT8                                 DeviceAddress,
 | 
						|
  IN  UINT8                                 EndPointAddress,
 | 
						|
  IN  UINT8                                 DeviceSpeed,
 | 
						|
  IN  UINTN                                 MaximumPacketLength,
 | 
						|
  IN  UINT8                                 DataBuffersNumber,
 | 
						|
  IN  OUT VOID                              *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
 | 
						|
  IN  UINTN                                 DataLength,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,
 | 
						|
  OUT UINT32                                *TransferResult
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Virtual interface to submits isochronous transfer to a target USB device
 | 
						|
    for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
    
 | 
						|
    UsbBusDev        - A pointer to bus controller of the device.
 | 
						|
    DeviceAddress    - Represents the address of the target device on the USB,
 | 
						|
                     which is assigned during USB enumeration.
 | 
						|
    EndPointAddress  - End point address
 | 
						|
    DeviceSpeed      - Indicates device speed.
 | 
						|
    MaximumPacketLength    - Indicates the maximum packet size that the 
 | 
						|
                           default control transfer endpoint is capable of 
 | 
						|
                           sending or receiving.
 | 
						|
    DataBuffersNumber - Number of data buffers prepared for the transfer.
 | 
						|
    Data              - Array of pointers to the buffers of data that will be 
 | 
						|
                      transmitted to USB device or received from USB device.
 | 
						|
    DataLength        - Indicates the size, in bytes, of the data buffer 
 | 
						|
                      specified by Data.
 | 
						|
    Translator        - A pointr to the transaction translator data.
 | 
						|
    TransferResult    - A pointer to the detailed result information generated 
 | 
						|
                      by this control transfer.               
 | 
						|
                      
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_UNSUPPORTED 
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UsbVirtualHcAsyncIsochronousTransfer (
 | 
						|
  IN  USB_BUS_CONTROLLER_DEVICE           *UsbBusDev,
 | 
						|
  IN  UINT8                               DeviceAddress,
 | 
						|
  IN  UINT8                               EndPointAddress,
 | 
						|
  IN  UINT8                               DeviceSpeed,
 | 
						|
  IN  UINTN                               MaximumPacketLength,
 | 
						|
  IN  UINT8                               DataBuffersNumber,
 | 
						|
  IN OUT VOID                             *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
 | 
						|
  IN  UINTN                               DataLength,
 | 
						|
  IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | 
						|
  IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,
 | 
						|
  IN  VOID                                *Context
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Routine Description:
 | 
						|
  
 | 
						|
    Vitual interface to submits Async isochronous transfer to a target USB device
 | 
						|
    for both Hc2 and Hc protocol.
 | 
						|
  
 | 
						|
  Arguments:
 | 
						|
  
 | 
						|
    UsbBusDev           - A pointer to bus controller of the device.
 | 
						|
    DeviceAddress       - Represents the address of the target device on the USB,
 | 
						|
                        which is assigned during USB enumeration.
 | 
						|
    EndPointAddress     - End point address
 | 
						|
    DeviceSpeed         - Indicates device speed.
 | 
						|
    MaximumPacketLength - Indicates the maximum packet size that the 
 | 
						|
                        default control transfer endpoint is capable of 
 | 
						|
                        sending or receiving.
 | 
						|
    DataBuffersNumber   - Number of data buffers prepared for the transfer.
 | 
						|
    Data                - Array of pointers to the buffers of data that will be transmitted 
 | 
						|
                        to USB device or received from USB device.
 | 
						|
    DataLength          - Indicates the size, in bytes, of the data buffer 
 | 
						|
                        specified by Data.
 | 
						|
    Translator          - A pointr to the transaction translator data.
 | 
						|
    IsochronousCallBack - When the transfer complete, the call back function will be called
 | 
						|
    Context             - Pass to the call back function as parameter
 | 
						|
                    
 | 
						|
  Returns:
 | 
						|
  
 | 
						|
    EFI_UNSUPPORTED 
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 |