summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Bus')
-rw-r--r--MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c2
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c95
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h18
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c50
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h1
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c32
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c76
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h2
-rw-r--r--MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c23
9 files changed, 210 insertions, 89 deletions
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
index ed1c4bf39..4f187e3ab 100644
--- a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
+++ b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
@@ -129,7 +129,7 @@ EnumerateNvmeDevNamespace (
Device->Media.WriteCaching = FALSE;
Flbas = NamespaceData->Flbas;
- LbaFmtIdx = Flbas & 3;
+ LbaFmtIdx = Flbas & 0xF;
Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;
Device->Media.BlockSize = (UINT32)1 << Lbads;
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
index 443df729d..5ca58fbb9 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
@@ -32,6 +32,13 @@ USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
{XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
};
+USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
+ {XHC_PORTSC_CSC, EfiUsbPortConnectChange},
+ {XHC_PORTSC_PEC, EfiUsbPortEnableChange},
+ {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},
+ {XHC_PORTSC_PRC, EfiUsbPortResetChange}
+};
+
USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {
{XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
{XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE},
@@ -46,6 +53,14 @@ USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {
{XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}
};
+USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
+ {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},
+ {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},
+ {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},
+ {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},
+ {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}
+};
+
EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding = {
XhcDriverBindingSupported,
XhcDriverBindingStart,
@@ -432,6 +447,14 @@ XhcGetRootHubPortStatus (
}
}
+ MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
+ XhcClearRootHubPortFeature (This, PortNumber, mUsbClearPortChangeMap[Index].Selector);
+ }
+ }
+
//
// Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
// For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
@@ -469,8 +492,6 @@ XhcSetRootHubPortFeature (
UINT32 Offset;
UINT32 State;
UINT32 TotalPort;
- UINT8 SlotId;
- USB_DEV_ROUTE RouteChart;
EFI_STATUS Status;
EFI_TPL OldTpl;
@@ -526,24 +547,13 @@ XhcSetRootHubPortFeature (
}
}
- RouteChart.Route.RouteString = 0;
- RouteChart.Route.RootPortNum = PortNumber + 1;
- RouteChart.Route.TierNum = 1;
//
- // If the port reset operation happens after the usb super speed device is enabled,
- // The subsequent configuration, such as getting device descriptor, will fail.
- // So here a workaround is introduced to skip the reset operation if the device is enabled.
+ // 4.3.1 Resetting a Root Hub Port
+ // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
//
- SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
- if (SlotId == 0) {
- //
- // 4.3.1 Resetting a Root Hub Port
- // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
- //
- State |= XHC_PORTSC_RESET;
- XhcWriteOpReg (Xhc, Offset, State);
- XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
- }
+ State |= XHC_PORTSC_RESET;
+ XhcWriteOpReg (Xhc, Offset, State);
+ XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
break;
case EfiUsbPortPower:
@@ -763,6 +773,8 @@ XhcControlTransfer (
UINTN MapSize;
EFI_USB_PORT_STATUS PortStatus;
UINT32 State;
+ EFI_USB_DEVICE_REQUEST ClearPortRequest;
+ UINTN Len;
//
// Validate parameters
@@ -808,6 +820,7 @@ XhcControlTransfer (
Status = EFI_DEVICE_ERROR;
*TransferResult = EFI_USB_ERR_SYSTEM;
+ Len = 0;
if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
DEBUG ((EFI_D_ERROR, "XhcControlTransfer: HC halted at entrance\n"));
@@ -839,6 +852,11 @@ XhcControlTransfer (
Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
}
}
+
+ if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto ON_EXIT;
+ }
//
// The actual device address has been assigned by XHCI during initializing the device slot.
// So we just need establish the mapping relationship between the device address requested from UsbBus
@@ -849,20 +867,6 @@ XhcControlTransfer (
Status = EFI_SUCCESS;
goto ON_EXIT;
}
-
- //
- // If the port reset operation happens after the usb super speed device is enabled,
- // The subsequent configuration, such as getting device descriptor, will fail.
- // So here a workaround is introduced to skip the reset operation if the device is enabled.
- //
- if ((Request->Request == USB_REQ_SET_FEATURE) &&
- (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER)) &&
- (Request->Value == EfiUsbPortReset)) {
- if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
- Status = EFI_SUCCESS;
- goto ON_EXIT;
- }
- }
//
// Create a new URB, insert it into the asynchronous
@@ -1050,6 +1054,33 @@ XhcControlTransfer (
}
}
+ MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
+
+ for (Index = 0; Index < MapSize; Index++) {
+ if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
+ ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
+ ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
+ ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE;
+ ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;
+ ClearPortRequest.Index = Request->Index;
+ ClearPortRequest.Length = 0;
+
+ XhcControlTransfer (
+ This,
+ DeviceAddress,
+ DeviceSpeed,
+ MaximumPacketLength,
+ &ClearPortRequest,
+ EfiUsbNoData,
+ NULL,
+ &Len,
+ Timeout,
+ Translator,
+ TransferResult
+ );
+ }
+ }
+
XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
*(UINT32 *)Data = *(UINT32*)&PortStatus;
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h
index 20a5510bf..dc8281198 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h
@@ -2,7 +2,7 @@
This file contains the register definition of XHCI host controller.
-Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@@ -169,7 +169,7 @@ typedef union {
#define XHC_PORTSC_RESET BIT4 // Port Reset
#define XHC_PORTSC_PLS (BIT5|BIT6|BIT7|BIT8) // Port Link State
#define XHC_PORTSC_PP BIT9 // Port Power
-#define XHC_PORTSC_PS (BIT10|BIT11|BIT12|BIT13) // Port Speed
+#define XHC_PORTSC_PS (BIT10|BIT11|BIT12) // Port Speed
#define XHC_PORTSC_LWS BIT16 // Port Link State Write Strobe
#define XHC_PORTSC_CSC BIT17 // Connect Status Change
#define XHC_PORTSC_PEC BIT18 // Port Enabled/Disabled Change
@@ -189,6 +189,7 @@ typedef union {
#define XHC_HUB_PORTSC_PEC BIT17 // Hub's Port Enabled/Disabled Change
#define XHC_HUB_PORTSC_OCC BIT19 // Hub's Over-Current Change
#define XHC_HUB_PORTSC_PRC BIT20 // Hub's Port Reset Change
+#define XHC_HUB_PORTSC_BHRC BIT21 // Hub's Port Warm Reset Change
#define XHC_IMAN_IP BIT0 // Interrupt Pending
#define XHC_IMAN_IE BIT1 // Interrupt Enable
@@ -196,6 +197,11 @@ typedef union {
#define XHC_IMODC_MASK 0xFFFF0000 // Interrupt Moderation Counter
//
+// Hub Class Feature Selector for Clear Port Feature Request
+//
+#define Usb3PortBHPortResetChange 29
+
+//
// Structure to map the hardware port states to the
// UEFI's port states.
//
@@ -204,6 +210,14 @@ typedef struct {
UINT16 UefiState;
} USB_PORT_STATE_MAP;
+//
+// Structure to map the hardware port states to feature selector for clear port feature request.
+//
+typedef struct {
+ UINT32 HwState;
+ UINT16 Selector;
+} USB_CLEAR_PORT_MAP;
+
/**
Read 1-byte width XHCI capability register.
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
index dea5b1af1..ec13e49a7 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
@@ -1105,25 +1105,25 @@ XhcCheckUrbResult (
CheckedUrb->Result |= EFI_USB_ERR_STALL;
CheckedUrb->Finished = TRUE;
DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));
- break;
+ goto EXIT;
case TRB_COMPLETION_BABBLE_ERROR:
CheckedUrb->Result |= EFI_USB_ERR_BABBLE;
CheckedUrb->Finished = TRUE;
DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));
- break;
+ goto EXIT;
case TRB_COMPLETION_DATA_BUFFER_ERROR:
CheckedUrb->Result |= EFI_USB_ERR_BUFFER;
CheckedUrb->Finished = TRUE;
DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));
- break;
+ goto EXIT;
case TRB_COMPLETION_USB_TRANSACTION_ERROR:
CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
CheckedUrb->Finished = TRUE;
DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));
- break;
+ goto EXIT;
case TRB_COMPLETION_SHORT_PACKET:
case TRB_COMPLETION_SUCCESS:
@@ -1144,7 +1144,7 @@ XhcCheckUrbResult (
DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));
CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
CheckedUrb->Finished = TRUE;
- break;
+ goto EXIT;
}
//
@@ -1535,6 +1535,10 @@ XhcPollPortStatusChange (
Status = EFI_SUCCESS;
+ if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
+ return EFI_SUCCESS;
+ }
+
if (ParentRouteChart.Dword == 0) {
RouteChart.Route.RouteString = 0;
RouteChart.Route.RootPortNum = Port + 1;
@@ -1549,6 +1553,15 @@ XhcPollPortStatusChange (
RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;
}
+ SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
+ if (SlotId != 0) {
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcDisableSlotCmd (Xhc, SlotId);
+ } else {
+ Status = XhcDisableSlotCmd64 (Xhc, SlotId);
+ }
+ }
+
if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
//
@@ -1566,26 +1579,15 @@ XhcPollPortStatusChange (
// Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
//
SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
- if (SlotId == 0) {
+ if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
if (Xhc->HcCParams.Data.Csz == 0) {
Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
} else {
Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
}
}
- } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) {
- //
- // Device is detached. Disable the allocated device slot and release resource.
- //
- SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
- if (SlotId != 0) {
- if (Xhc->HcCParams.Data.Csz == 0) {
- Status = XhcDisableSlotCmd (Xhc, SlotId);
- } else {
- Status = XhcDisableSlotCmd64 (Xhc, SlotId);
- }
- }
- }
+ }
+
return Status;
}
@@ -2633,9 +2635,10 @@ XhcSetConfigCmd (
if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
Interval = EpDesc->Interval;
//
- // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
+ // Calculate through the bInterval field of Endpoint descriptor.
//
- InputContext->EP[Dci-1].Interval = 6;
+ ASSERT (Interval != 0);
+ InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
} else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
Interval = EpDesc->Interval;
ASSERT (Interval >= 1 && Interval <= 16);
@@ -2830,9 +2833,10 @@ XhcSetConfigCmd64 (
if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {
Interval = EpDesc->Interval;
//
- // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.
+ // Calculate through the bInterval field of Endpoint descriptor.
//
- InputContext->EP[Dci-1].Interval = 6;
+ ASSERT (Interval != 0);
+ InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;
} else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {
Interval = EpDesc->Interval;
ASSERT (Interval >= 1 && Interval <= 16);
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
index d503a278a..9ede83ab7 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h
@@ -198,6 +198,7 @@ struct _USB_DEVICE {
USB_INTERFACE *ParentIf;
UINT8 ParentPort; // Start at 0
UINT8 Tier;
+ BOOLEAN DisconnectFail;
};
//
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
index b2401ca40..9687eb0bc 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c
@@ -142,15 +142,15 @@ UsbFreeDevDesc (
VOID *
UsbCreateDesc (
IN UINT8 *DescBuf,
- IN INTN Len,
+ IN UINTN Len,
IN UINT8 Type,
- OUT INTN *Consumed
+ OUT UINTN *Consumed
)
{
USB_DESC_HEAD *Head;
- INTN DescLen;
- INTN CtrlLen;
- INTN Offset;
+ UINTN DescLen;
+ UINTN CtrlLen;
+ UINTN Offset;
VOID *Desc;
DescLen = 0;
@@ -188,7 +188,15 @@ UsbCreateDesc (
while ((Offset < Len) && (Head->Type != Type)) {
Offset += Head->Len;
+ if (Len <= Offset) {
+ DEBUG (( EFI_D_ERROR, "UsbCreateDesc: met mal-format descriptor, Beyond boundary!\n"));
+ return NULL;
+ }
Head = (USB_DESC_HEAD*)(DescBuf + Offset);
+ if (Head->Len == 0) {
+ DEBUG (( EFI_D_ERROR, "UsbCreateDesc: met mal-format descriptor, Head->Len = 0!\n"));
+ return NULL;
+ }
}
if ((Len <= Offset) || (Len < Offset + DescLen) ||
@@ -223,16 +231,16 @@ UsbCreateDesc (
USB_INTERFACE_SETTING *
UsbParseInterfaceDesc (
IN UINT8 *DescBuf,
- IN INTN Len,
- OUT INTN *Consumed
+ IN UINTN Len,
+ OUT UINTN *Consumed
)
{
USB_INTERFACE_SETTING *Setting;
USB_ENDPOINT_DESC *Ep;
UINTN Index;
UINTN NumEp;
- INTN Used;
- INTN Offset;
+ UINTN Used;
+ UINTN Offset;
*Consumed = 0;
Setting = UsbCreateDesc (DescBuf, Len, USB_DESC_TYPE_INTERFACE, &Used);
@@ -265,7 +273,7 @@ UsbParseInterfaceDesc (
//
// Create the endpoints for this interface
//
- for (Index = 0; Index < NumEp; Index++) {
+ for (Index = 0; (Index < NumEp) && (Offset < Len); Index++) {
Ep = UsbCreateDesc (DescBuf + Offset, Len - Offset, USB_DESC_TYPE_ENDPOINT, &Used);
if (Ep == NULL) {
@@ -300,7 +308,7 @@ ON_ERROR:
USB_CONFIG_DESC *
UsbParseConfigDesc (
IN UINT8 *DescBuf,
- IN INTN Len
+ IN UINTN Len
)
{
USB_CONFIG_DESC *Config;
@@ -308,7 +316,7 @@ UsbParseConfigDesc (
USB_INTERFACE_DESC *Interface;
UINTN Index;
UINTN NumIf;
- INTN Consumed;
+ UINTN Consumed;
ASSERT (DescBuf != NULL);
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
index 79635cb18..430f5aa3d 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
@@ -450,7 +450,7 @@ UsbSelectConfig (
@param UsbIf The interface to disconnect driver from.
**/
-VOID
+EFI_STATUS
UsbDisconnectDriver (
IN USB_INTERFACE *UsbIf
)
@@ -462,8 +462,9 @@ UsbDisconnectDriver (
// Release the hub if it's a hub controller, otherwise
// disconnect the driver if it is managed by other drivers.
//
+ Status = EFI_SUCCESS;
if (UsbIf->IsHub) {
- UsbIf->HubApi->Release (UsbIf);
+ Status = UsbIf->HubApi->Release (UsbIf);
} else if (UsbIf->IsManaged) {
//
@@ -479,13 +480,17 @@ UsbDisconnectDriver (
gBS->RestoreTPL (TPL_CALLBACK);
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));
ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK);
gBS->RaiseTPL (OldTpl);
}
+
+ return Status;
}
@@ -495,17 +500,20 @@ UsbDisconnectDriver (
@param Device The USB device to remove configuration from.
**/
-VOID
+EFI_STATUS
UsbRemoveConfig (
IN USB_DEVICE *Device
)
{
USB_INTERFACE *UsbIf;
UINTN Index;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
//
// Remove each interface of the device
//
+ ReturnStatus = EFI_SUCCESS;
for (Index = 0; Index < Device->NumOfInterface; Index++) {
ASSERT (Index < USB_MAX_INTERFACE);
UsbIf = Device->Interfaces[Index];
@@ -514,13 +522,17 @@ UsbRemoveConfig (
continue;
}
- UsbDisconnectDriver (UsbIf);
- UsbFreeInterface (UsbIf);
- Device->Interfaces[Index] = NULL;
+ Status = UsbDisconnectDriver (UsbIf);
+ if (!EFI_ERROR (Status)) {
+ UsbFreeInterface (UsbIf);
+ Device->Interfaces[Index] = NULL;
+ } else {
+ ReturnStatus = Status;
+ }
}
Device->ActiveConfig = NULL;
- Device->NumOfInterface = 0;
+ return ReturnStatus;
}
@@ -540,6 +552,7 @@ UsbRemoveDevice (
USB_BUS *Bus;
USB_DEVICE *Child;
EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
UINTN Index;
Bus = Device->Bus;
@@ -548,6 +561,7 @@ UsbRemoveDevice (
// Remove all the devices on its downstream ports. Search from devices[1].
// Devices[0] is the root hub.
//
+ ReturnStatus = EFI_SUCCESS;
for (Index = 1; Index < Bus->MaxDevices; Index++) {
Child = Bus->Devices[Index];
@@ -557,21 +571,31 @@ UsbRemoveDevice (
Status = UsbRemoveDevice (Child);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "UsbRemoveDevice: failed to remove child, ignore error\n"));
+ if (!EFI_ERROR (Status)) {
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);
- Bus->Devices[Device->Address] = NULL;
- UsbFreeDevice (Device);
+ if (!EFI_ERROR (Status)) {
+ DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address));
- 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 Bit;
UINT8 Index;
-
+ USB_DEVICE *Child;
+
ASSERT (Context != NULL);
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) {
return ;
}
@@ -1015,10 +1048,17 @@ UsbRootHubEnumeration (
{
USB_INTERFACE *RootHub;
UINT8 Index;
+ USB_DEVICE *Child;
RootHub = (USB_INTERFACE *) Context;
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);
}
}
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h
index 288d38f63..ef7d44091 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h
@@ -151,7 +151,7 @@ UsbSelectConfig (
@return None.
**/
-VOID
+EFI_STATUS
UsbRemoveConfig (
IN USB_DEVICE *Device
);
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
index 9e5299c0e..e3752d1f8 100644
--- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
+++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c
@@ -968,6 +968,15 @@ UsbHubResetPort (
UINTN Index;
EFI_STATUS Status;
+ Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ } else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
+ DEBUG (( EFI_D_INFO, "UsbHubResetPort: skip reset on hub %p port %d\n", HubIf, Port));
+ return EFI_SUCCESS;
+ }
+
Status = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);
if (EFI_ERROR (Status)) {
@@ -988,6 +997,10 @@ UsbHubResetPort (
for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
if (!EFI_ERROR (Status) &&
USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
gBS->Stall (USB_SET_PORT_RECOVERY_STALL);
@@ -1268,6 +1281,16 @@ UsbRootHubResetPort (
// should be handled in the EHCI driver.
//
Bus = RootIf->Device->Bus;
+
+ Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ } else if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
+ DEBUG (( EFI_D_INFO, "UsbRootHubResetPort: skip reset on root port %d\n", Port));
+ return EFI_SUCCESS;
+ }
+
Status = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);
if (EFI_ERROR (Status)) {