⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbbus.c

📁 Next BIOS Source code : Extensible Firmware Interface
💻 C
📖 第 1 页 / 共 4 页
字号:
        (UINT32 *)&HubPortStatus
      );

      if (IsPortConnect(HubPortStatus.PortStatus)) {

        DEBUG ((EFI_D_USB, "New Device Connect on Hub port \n"));
        
        //
        // 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 = NULL;
        Status = gBS->AllocatePool(
                        EfiBootServicesData,
                        sizeof(USB_IO_DEVICE),
                        (VOID **)&NewDevice
                      );

        if (EFI_ERROR (Status)) {
          return;
        }

        EfiZeroMem(NewDevice, sizeof(USB_IO_DEVICE));

        //
        // Initialize some fields
        //
        NewDevice->IsSlowDevice = \
             IsPortLowSpeedDeviceAttached(HubPortStatus.PortStatus);

        NewDevice->DeviceDescriptor.MaxPacketSize0 = 8;
        NewDevice->BusController = HubController->UsbDevice->BusController;

        //
        // There is something connected to this port,
        // reset that port
        //
        HubSetPortFeature(
          UsbIo,
          StatusChangePort,
          EfiUsbPortReset
        );

        gBS->Stall(50 * 1000);

        //
        // Wait for port reset complete
        //
        n = 10;
        do {
          HubGetPortStatus(
            UsbIo,
            StatusChangePort,
            (UINT32 *)&HubPortStatus
          );
          gBS->Stall(10 * 100);
          n -= 1;
        }while((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET ) == 0 && n > 0);

        if (n == 0) {
          //
          // Cannot reset port, return error
          //
          gBS->FreePool (NewDevice);
          return;
        }

        //
        // reset port will cause some bits change, clear them
        //
        if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_ENABLE) {
           DEBUG ((EFI_D_USB, "Port Enable Change\n"));
           HubClearPortFeature(
             UsbIo,
             StatusChangePort,
             EfiUsbPortEnableChange
           );

          HubGetPortStatus(
            UsbIo,
            StatusChangePort,
            (UINT32 *)&HubPortStatus
          );
        }

        if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) {
          DEBUG ((EFI_D_USB, "Port Reset Change\n"));
          HubClearPortFeature(
            UsbIo,
            StatusChangePort,
            EfiUsbPortResetChange
          );
          HubGetPortStatus(
            UsbIo,
            StatusChangePort,
            (UINT32 *)&HubPortStatus
          );
        }

        //
        // 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 (j = 0; j < NewDevice->NumOfControllers; j++) {
          //
          // If this device is hub, add to the hub index
          //
          NewController = NewDevice->UsbController[j];

          //
          // 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,
                   UsbEnumeration,
                   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 ((EFI_D_USB, "Something Device Detached on Hub port\n"));

        OldUsbIoDevice = HubController->Children[StatusChangePort - 1];

        UsbDeviceDeConfiguration (OldUsbIoDevice);

        HubController->Children[StatusChangePort - 1] = NULL;

      }

      return;
    }

    return;
  }
}


//
// Clear port connection change status over a given root hub port
//
VOID
ClearRootPortConnectionChangeStatus (
  UINT8                   PortNum,
  EFI_USB_HC_PROTOCOL     *UsbHCInterface
)
/*++

  Routine Description:
    Clear port connection change status over a given root hub port

  Parameters:
    PortNum         -   The given port.
    UsbHCInterface  -   The EFI_USB_HC_PROTOCOL instance.

  Return Value:
    N/A

--*/
{
  UsbHCInterface->ClearRootHubPortFeature(
                    UsbHCInterface,
                    PortNum,
                    EfiUsbPortConnectChange
                  );
}

STATIC
USB_IO_CONTROLLER_DEVICE *
CreateUsbIoControllerDevice (
  VOID
)
/*++

  Routine Description:
    Allocate a structure for USB_IO_CONTROLLER_DEVICE

  Parameters:
    N/A

  Return Value:
    A pointer to a USB_IO_CONTROLLER_DEVICE structure,
    Or NULL.

--*/
{
  USB_IO_CONTROLLER_DEVICE  *UsbIoControllerDev;
  EFI_STATUS                Status;

  //
  // Allocate USB_IO_CONTROLLER_DEVICE structure
  //
  UsbIoControllerDev = NULL;
  Status = gBS->AllocatePool(
                  EfiBootServicesData,
                  sizeof(USB_IO_CONTROLLER_DEVICE),
                  (VOID **)&UsbIoControllerDev
                );

  if (EFI_ERROR(Status)) {
    return NULL;
  }

  EfiZeroMem (UsbIoControllerDev, sizeof(USB_IO_CONTROLLER_DEVICE));

  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.

  Parameters:
    UsbIoController   -   The Controller to be operated.

  Return Value:
    EFI_SUCCESS
    Others

--*/
{
  USB_DEVICE_PATH             UsbNode;
  EFI_STATUS                  Status;
  EFI_DEVICE_PATH_PROTOCOL    *ParentDevicePath;
  EFI_USB_HC_PROTOCOL         *UsbHcProtocol;
  
  //
  // 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;
  }
  
  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
  )
/*++

  Routine Description:
    Reset parent hub port to which this device is connected.

  Parameters:
    UsbIoController   -   Indicating the Usb Controller Device.
    Reconfigure       -   Do we need to reconfigure it.

  Return Value:
    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;

  if (UsbIoController->IsUsbHub) {
    return EFI_INVALID_PARAMETER;
  }

  if (ParentIoDev->DeviceAddress == 1) {
    //
    // Send RESET signal from Root Hub Port
    //
    DEBUG ((EFI_D_USB, "\n"));
    ResetRootPort(HubPort, ParentIoDev->BusController->UsbHCInterface);
  } else {

    //
    // Send RESET signal from Hub Port
    //
    DEBUG ((EFI_D_USB, "\n"));
    HubSetPortFeature(
      &ParentController->UsbIo,
      (UINT8)(HubPort + 1),
      EfiUsbPortReset
    );
  }

  gBS->Stall (50 * 1000);

  //
  // 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
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.

  Parameters:
    This          -   Indicates the calling context.

  Return Value:
    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);

  return Status;
}

VOID
ResetRootPort(
  UINT8                  PortNum,
  EFI_USB_HC_PROTOCOL    *UsbHCInterface
  )
/*++

  Routine Description:
    Reset Root Hub port.

  Parameters:
    PortNum         -   The given port to be reset.
    UsbHCInterface  -   The EFI_USB_HC_PROTOCOL instance.

  Return Value:
    N/A

--*/
{
  EFI_USB_PORT_STATUS     PortStatus;

  UsbHCInterface->GetRootHubPortStatus(
                    UsbHCInterface,
                    PortNum,
                    &PortStatus
                  );

  //
  // reset root port
  //
  UsbHCInterface->SetRootHubPortFeature(
                    UsbHCInterface,
                    PortNum,
                    EfiUsbPortReset
                  );

  gBS->Stall(200 * 1000);

  //
  // clear reset root port
  //
  UsbHCInterface->ClearRootHubPortFeature(
                    UsbHCInterface,
                    PortNum,
                    EfiUsbPortReset
                  );

  gBS->Stall (1000);

  ClearRootPortConnectionChangeStatus (PortNum, UsbHCInterface);

  //
  // Set port enable
  //
  UsbHCInterface->SetRootHubPortFeature(
                    UsbHCInterface,
                    PortNum,
                    EfiUsbPortEnable
                  );

  gBS->Stall(500);

  return;
}

⌨️ 快捷键说明

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