MdeMdeModulePkg/UsbBusDxe: If DisconnectController() returns an error the USB Bus Driver would retry the DisconnectController() from a timer event until it succeeds

Signed-off-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>



git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14819 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Feng Tian 2013-10-30 03:49:24 +00:00 committed by erictian
parent 95d0cb1403
commit 127884c52a
4 changed files with 64 additions and 19 deletions

View File

@ -198,6 +198,7 @@ struct _USB_DEVICE {
USB_INTERFACE *ParentIf; USB_INTERFACE *ParentIf;
UINT8 ParentPort; // Start at 0 UINT8 ParentPort; // Start at 0
UINT8 Tier; UINT8 Tier;
BOOLEAN DisconnectFail;
}; };
// //

View File

@ -450,7 +450,7 @@ UsbSelectConfig (
@param UsbIf The interface to disconnect driver from. @param UsbIf The interface to disconnect driver from.
**/ **/
VOID EFI_STATUS
UsbDisconnectDriver ( UsbDisconnectDriver (
IN USB_INTERFACE *UsbIf IN USB_INTERFACE *UsbIf
) )
@ -462,8 +462,9 @@ UsbDisconnectDriver (
// Release the hub if it's a hub controller, otherwise // Release the hub if it's a hub controller, otherwise
// disconnect the driver if it is managed by other drivers. // disconnect the driver if it is managed by other drivers.
// //
Status = EFI_SUCCESS;
if (UsbIf->IsHub) { if (UsbIf->IsHub) {
UsbIf->HubApi->Release (UsbIf); Status = UsbIf->HubApi->Release (UsbIf);
} else if (UsbIf->IsManaged) { } else if (UsbIf->IsManaged) {
// //
@ -479,13 +480,17 @@ UsbDisconnectDriver (
gBS->RestoreTPL (TPL_CALLBACK); gBS->RestoreTPL (TPL_CALLBACK);
Status = gBS->DisconnectController (UsbIf->Handle, NULL, NULL); Status = gBS->DisconnectController (UsbIf->Handle, NULL, NULL);
UsbIf->IsManaged = FALSE; if (!EFI_ERROR (Status)) {
UsbIf->IsManaged = FALSE;
}
DEBUG (( EFI_D_INFO, "UsbDisconnectDriver: TPL after disconnect is %d, %d\n", (UINT32)UsbGetCurrentTpl(), Status)); DEBUG (( EFI_D_INFO, "UsbDisconnectDriver: TPL after disconnect is %d, %d\n", (UINT32)UsbGetCurrentTpl(), Status));
ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK); ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
gBS->RaiseTPL (OldTpl); gBS->RaiseTPL (OldTpl);
} }
return Status;
} }
@ -495,17 +500,20 @@ UsbDisconnectDriver (
@param Device The USB device to remove configuration from. @param Device The USB device to remove configuration from.
**/ **/
VOID EFI_STATUS
UsbRemoveConfig ( UsbRemoveConfig (
IN USB_DEVICE *Device IN USB_DEVICE *Device
) )
{ {
USB_INTERFACE *UsbIf; USB_INTERFACE *UsbIf;
UINTN Index; UINTN Index;
EFI_STATUS Status;
EFI_STATUS ReturnStatus;
// //
// Remove each interface of the device // Remove each interface of the device
// //
ReturnStatus = EFI_SUCCESS;
for (Index = 0; Index < Device->NumOfInterface; Index++) { for (Index = 0; Index < Device->NumOfInterface; Index++) {
ASSERT (Index < USB_MAX_INTERFACE); ASSERT (Index < USB_MAX_INTERFACE);
UsbIf = Device->Interfaces[Index]; UsbIf = Device->Interfaces[Index];
@ -514,13 +522,17 @@ UsbRemoveConfig (
continue; continue;
} }
UsbDisconnectDriver (UsbIf); Status = UsbDisconnectDriver (UsbIf);
UsbFreeInterface (UsbIf); if (!EFI_ERROR (Status)) {
Device->Interfaces[Index] = NULL; UsbFreeInterface (UsbIf);
Device->Interfaces[Index] = NULL;
} else {
ReturnStatus = Status;
}
} }
Device->ActiveConfig = NULL; Device->ActiveConfig = NULL;
Device->NumOfInterface = 0; return ReturnStatus;
} }
@ -540,6 +552,7 @@ UsbRemoveDevice (
USB_BUS *Bus; USB_BUS *Bus;
USB_DEVICE *Child; USB_DEVICE *Child;
EFI_STATUS Status; EFI_STATUS Status;
EFI_STATUS ReturnStatus;
UINTN Index; UINTN Index;
Bus = Device->Bus; Bus = Device->Bus;
@ -548,6 +561,7 @@ UsbRemoveDevice (
// Remove all the devices on its downstream ports. Search from devices[1]. // Remove all the devices on its downstream ports. Search from devices[1].
// Devices[0] is the root hub. // Devices[0] is the root hub.
// //
ReturnStatus = EFI_SUCCESS;
for (Index = 1; Index < Bus->MaxDevices; Index++) { for (Index = 1; Index < Bus->MaxDevices; Index++) {
Child = Bus->Devices[Index]; Child = Bus->Devices[Index];
@ -557,21 +571,31 @@ UsbRemoveDevice (
Status = UsbRemoveDevice (Child); Status = UsbRemoveDevice (Child);
if (EFI_ERROR (Status)) { if (!EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UsbRemoveDevice: failed to remove child, ignore error\n"));
Bus->Devices[Index] = NULL; Bus->Devices[Index] = NULL;
} else {
Bus->Devices[Index]->DisconnectFail = TRUE;
ReturnStatus = Status;
DEBUG ((EFI_D_INFO, "UsbRemoveDevice: failed to remove child %p at parent %p\n", Child, Device));
} }
} }
UsbRemoveConfig (Device); if (EFI_ERROR (ReturnStatus)) {
return ReturnStatus;
}
DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address)); Status = UsbRemoveConfig (Device);
ASSERT (Device->Address < Bus->MaxDevices); if (!EFI_ERROR (Status)) {
Bus->Devices[Device->Address] = NULL; DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address));
UsbFreeDevice (Device);
return EFI_SUCCESS; ASSERT (Device->Address < Bus->MaxDevices);
Bus->Devices[Device->Address] = NULL;
UsbFreeDevice (Device);
} else {
Bus->Devices[Device->Address]->DisconnectFail = TRUE;
}
return Status;
} }
@ -968,11 +992,20 @@ UsbHubEnumeration (
UINT8 Byte; UINT8 Byte;
UINT8 Bit; UINT8 Bit;
UINT8 Index; UINT8 Index;
USB_DEVICE *Child;
ASSERT (Context != NULL); ASSERT (Context != NULL);
HubIf = (USB_INTERFACE *) Context; HubIf = (USB_INTERFACE *) Context;
for (Index = 0; Index < HubIf->NumOfPort; Index++) {
Child = UsbFindChild (HubIf, Index);
if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {
DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from hub %p, try again\n", Index, HubIf));
UsbRemoveDevice (Child);
}
}
if (HubIf->ChangeMap == NULL) { if (HubIf->ChangeMap == NULL) {
return ; return ;
} }
@ -1015,10 +1048,17 @@ UsbRootHubEnumeration (
{ {
USB_INTERFACE *RootHub; USB_INTERFACE *RootHub;
UINT8 Index; UINT8 Index;
USB_DEVICE *Child;
RootHub = (USB_INTERFACE *) Context; RootHub = (USB_INTERFACE *) Context;
for (Index = 0; Index < RootHub->NumOfPort; Index++) { for (Index = 0; Index < RootHub->NumOfPort; Index++) {
Child = UsbFindChild (RootHub, Index);
if ((Child != NULL) && (Child->DisconnectFail == TRUE)) {
DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from root hub %p, try again\n", Index, RootHub));
UsbRemoveDevice (Child);
}
UsbEnumeratePort (RootHub, Index); UsbEnumeratePort (RootHub, Index);
} }
} }

View File

@ -151,7 +151,7 @@ UsbSelectConfig (
@return None. @return None.
**/ **/
VOID EFI_STATUS
UsbRemoveConfig ( UsbRemoveConfig (
IN USB_DEVICE *Device IN USB_DEVICE *Device
); );

View File

@ -988,6 +988,10 @@ UsbHubResetPort (
for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) { for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
Status = UsbHubGetPortStatus (HubIf, Port, &PortState); Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
if (EFI_ERROR (Status)) {
return Status;
}
if (!EFI_ERROR (Status) && if (!EFI_ERROR (Status) &&
USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) { USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
gBS->Stall (USB_SET_PORT_RECOVERY_STALL); gBS->Stall (USB_SET_PORT_RECOVERY_STALL);