📄 usbbus.c
字号:
// 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 ((EFI_D_USB, "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 (i = 0; i < UsbController->DownstreamPorts; i++) {
if (UsbController->Children[i]) {
ChildDevice = UsbController->Children[i];
UsbDeviceDeConfiguration(ChildDevice);
UsbController->Children[i] = 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
//
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
);
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
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.
Parameter:
Data - Hub interrupt transfer data.
DataLength - The length of the Data.
Context - Hub Controller Device.
Result - Hub interrupt transfer status.
Return Value:
EFI_SUCCESS
EFI_DEVICE_ERROR
--*/
{
USB_IO_CONTROLLER_DEVICE *HubController;
UINT8 i;
UINT8 *ptr;
EFI_USB_IO_PROTOCOL *UsbIo;
UINT32 UsbResult;
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
);
UsbIo->UsbAsyncInterruptTransfer(
UsbIo,
HubController->HubEndpointAddress,
TRUE,
100,
1, //Hub ports < 7
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 (i = 0; i < DataLength * 8; i++) {
ptr = (UINT8 *)Data + i /8;
if ((*ptr) & (1 << (i % 8))) {
HubController->StatusChangePort = i;
break;
}
}
//
//Signal hub notify event
//
gBS->SignalEvent (HubController->HubNotify);
return EFI_SUCCESS;
}
//
// USB Root Hub Enumerator
//
STATIC
VOID
UsbEnumeration (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
This is USB enumerator
Arguments:
Event: Indicating which event is signaled
Context: actually it is a USB_IO_DEVICE
Returns:
EFI_SUCCESS
Others
--*/
{
USB_IO_CONTROLLER_DEVICE *HubController;
EFI_USB_PORT_STATUS HubPortStatus;
EFI_STATUS Status;
UINT8 i;
EFI_USB_HC_PROTOCOL *UsbHCInterface;
USB_IO_DEVICE *UsbIoDev;
EFI_HANDLE HostController;
USB_IO_DEVICE *OldUsbIoDevice;
USB_IO_DEVICE *NewDevice;
USB_IO_CONTROLLER_DEVICE *NewController;
UINT8 j;
UINT8 n;
EFI_USB_IO_PROTOCOL *UsbIo;
UINT8 StatusChangePort;
HubController = (USB_IO_CONTROLLER_DEVICE *)Context;
HostController = HubController->HostController;
if (HubController->UsbDevice->DeviceAddress == 1) {
//
// Root hub has the address 1
//
UsbIoDev = HubController->UsbDevice;
UsbHCInterface = UsbIoDev->BusController->UsbHCInterface;
for (i = 0; i < HubController->DownstreamPorts; i++) {
UsbHCInterface->GetRootHubPortStatus (
UsbHCInterface,
i,
(EFI_USB_PORT_STATUS *)&HubPortStatus
);
if (!IsPortConnectChange(HubPortStatus.PortChangeStatus)) {
continue;
}
//
//Clear root hub status change status
//
ClearRootPortConnectionChangeStatus(
i,
UsbHCInterface
);
UsbHCInterface->GetRootHubPortStatus (
UsbHCInterface,
i,
(EFI_USB_PORT_STATUS *)&HubPortStatus
);
if (IsPortConnect(HubPortStatus.PortStatus)) {
//
// There is something connected to this port
//
DEBUG ((EFI_D_USB, "Something attached from Root Hub\n"));
//
// if there is something physically detached, but still logically
// attached...
//
OldUsbIoDevice = HubController->Children[i];
if (NULL != OldUsbIoDevice) {
UsbDeviceDeConfiguration(OldUsbIoDevice);
HubController->Children[i] = NULL;
}
//
// Reset the port.
//
ResetRootPort(
i,
UsbHCInterface
);
UsbHCInterface->GetRootHubPortStatus (
UsbHCInterface,
i,
(EFI_USB_PORT_STATUS *)&HubPortStatus
);
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 by copying data from
// its parents
//
NewDevice->IsSlowDevice = \
IsPortLowSpeedDeviceAttached (HubPortStatus.PortStatus);
NewDevice->DeviceDescriptor.MaxPacketSize0 = 8;
NewDevice->BusController = UsbIoDev->BusController;
//
// Configure that device
//
Status = UsbDeviceConfiguration(
HubController,
HostController,
i,
NewDevice
);
if (EFI_ERROR (Status)) {
gBS->FreePool (NewDevice);
return;
}
//
// Add this device to the usb bus tree
//
HubController->Children[i] = NewDevice;
for (j = 0; j < NewDevice->NumOfControllers; j++) {
//
// If this device is hub, add to the hub index
//
NewController = NewDevice->UsbController[j];
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,
UsbEnumeration,
NewController,
&NewController->HubNotify
);
//
// Add request to do query hub status
// change endpoint
//
UsbIo = &NewController->UsbIo;
UsbIo->UsbAsyncInterruptTransfer(
UsbIo,
NewController->HubEndpointAddress,
TRUE,
100,
1, //Hub ports < 7
OnHubInterruptComplete,
NewController
);
}
}
} else {
//
// Something disconnected from USB root hub
//
DEBUG ((EFI_D_USB, "Something deteached from Root Hub\n"));
OldUsbIoDevice = HubController->Children[i];
UsbDeviceDeConfiguration(OldUsbIoDevice);
HubController->Children[i] = NULL;
UsbHCInterface->ClearRootHubPortFeature(
UsbHCInterface,
i,
EfiUsbPortEnableChange
);
UsbHCInterface->GetRootHubPortStatus (
UsbHCInterface,
i,
(EFI_USB_PORT_STATUS *)&HubPortStatus
);
}
}
return;
} else {
//
// 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 ((EFI_D_USB, "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 ((EFI_D_USB, "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 ((EFI_D_USB, "Port Overcurrent Change\n"));
HubClearPortFeature(
UsbIo,
StatusChangePort,
EfiUsbPortOverCurrentChange
);
HubGetPortStatus(
UsbIo,
StatusChangePort,
(UINT32 *)&HubPortStatus
);
}
if (IsPortConnectChange(HubPortStatus.PortChangeStatus)) {
//
// First clear port connection change
//
DEBUG ((EFI_D_USB, "Port Connection Change\n"));
HubClearPortFeature(
UsbIo,
StatusChangePort,
EfiUsbPortConnectChange
);
HubGetPortStatus(
UsbIo,
StatusChangePort,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -