📄 usbbus.c
字号:
(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 + -