usbbus.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,516 行 · 第 1/5 页

C
2,516
字号
        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  = EfiLibAllocateZeroPool (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         
    EFI_OUT_OF_RESOURCES

--*/
{
  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
  //
  EfiZeroMem (&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 = EfiAppendDevicePathNode (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,
                    &Usb2HcProtocol,
                    gUsbBusDriverBinding.DriverBindingHandle,
                    UsbIoController->Handle,
                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
                    );
  } else {
    Status = gBS->OpenProtocol (
                    UsbIoController->HostController,
                    &gEfiUsbHcProtocolGuid,
                    &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;

  UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This);

  if (IsHub (UsbIoController)) {
    return EFI_INVALID_PARAMETER;
  }
  
  //
  // Since at this time, this device has already been configured,
  // it needs to be re-configured.
  //
  return ParentPortReset (UsbIoController, TRUE, 0);
}

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;

  HubSetPor

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?