usbbus.c

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

C
2,516
字号
  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;

  if (UsbIoDevice->DeviceSpeed != EFI_USB_SPEED_HIGH) {
    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
    //
    EfiCopyMem (
      &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
        );
    }
    //

⌨️ 快捷键说明

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