[USBOHCI]

- Remove massive hacks from our port reset code
- We now wait for the reset complete interrupt instead of stalling 10ms and continuing
- Don't wait for a port to stabilize unless there's actually a device connected
[USBEHCI]
- Fix very long delay between setting the reset bit and clearing it
- Wait for the port to come back enabled before finishing the reset
- Don't wait for a port to stabilize unless there's actually a device connected

svn path=/trunk/; revision=55662
This commit is contained in:
Cameron Gutman 2012-02-17 03:45:46 +00:00
parent c1c3ea3ac8
commit 075cf8cdc9
2 changed files with 43 additions and 57 deletions

View file

@ -977,20 +977,9 @@ CUSBHardwareDevice::ResetPort(
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), PortStatus);
//
// delay is 20 ms for port reset as per USB 2.0 spec
// Wait for reset to start
//
Timeout.QuadPart = 20;
DPRINT1("Waiting %d milliseconds for port reset\n", Timeout.LowPart);
//
// convert to 100 ns units (absolute)
//
Timeout.QuadPart *= -10000;
//
// perform the wait
//
KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
KeStallExecutionProcessor(100);
//
// Clear reset
@ -1042,13 +1031,24 @@ CUSBHardwareDevice::ResetPort(
}
//
// this must be enabled now
// this will be enabled now since we're high-speed
//
if (PortStatus & EHCI_PRT_ENABLED)
do
{
DPRINT1("Port is not enabled after reset\n");
//ASSERT(FALSE);
}
//
// wait
//
KeStallExecutionProcessor(100);
//
// Check that the port is enabled
//
PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
if (PortStatus & EHCI_PRT_ENABLED)
break;
} while (TRUE);
DPRINT1("Port is back up after reset\n");
return STATUS_SUCCESS;
}
@ -1143,6 +1143,13 @@ CUSBHardwareDevice::ClearPortStatus(
if (PortId > m_Capabilities.HCSParams.PortCount)
return STATUS_UNSUCCESSFUL;
//
// reset status change bits
//
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
Value |= EHCI_PRT_CONNECTSTATUSCHANGE | EHCI_PRT_ENABLEDSTATUSCHANGE;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
if (Status == C_PORT_RESET)
{
//
@ -1151,17 +1158,10 @@ CUSBHardwareDevice::ClearPortStatus(
m_ResetInProgress[PortId] = FALSE;
}
if (Status == C_PORT_CONNECTION)
if (Status == C_PORT_CONNECTION && (Value & EHCI_PRT_CONNECTED))
{
LARGE_INTEGER Timeout;
//
// reset status change bits
//
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
Value |= EHCI_PRT_CONNECTSTATUSCHANGE | EHCI_PRT_ENABLEDSTATUSCHANGE;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
//
// delay is 100 ms
//

View file

@ -1193,7 +1193,6 @@ CUSBHardwareDevice::ClearPortStatus(
return STATUS_UNSUCCESSFUL;
Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)));
KeStallExecutionProcessor(100);
if (Status == C_PORT_RESET)
{
@ -1223,7 +1222,7 @@ CUSBHardwareDevice::ClearPortStatus(
//
// wait for port to stabilize
//
if (Status == C_PORT_CONNECTION)
if (Status == C_PORT_CONNECTION && (Value & OHCI_RH_PORTSTATUS_CCS))
{
LARGE_INTEGER Timeout;
@ -1248,6 +1247,7 @@ CUSBHardwareDevice::ClearPortStatus(
//
// re-enable root hub change
//
DPRINT1("Enabling status change\n");
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_INTERRUPT_ENABLE_OFFSET), OHCI_ROOT_HUB_STATUS_CHANGE);
return STATUS_SUCCESS;
@ -1324,8 +1324,6 @@ CUSBHardwareDevice::SetPortFeature(
}
else if (Feature == PORT_RESET)
{
LARGE_INTEGER Timeout;
//
// assert
//
@ -1343,7 +1341,8 @@ CUSBHardwareDevice::SetPortFeature(
//
Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)));
if ((Value & OHCI_RH_PORTSTATUS_PRS) == 0)
if ((Value & OHCI_RH_PORTSTATUS_PRS) == 0 &&
(Value & OHCI_RH_PORTSTATUS_PRSC) != 0)
{
//
// reset is complete
@ -1357,32 +1356,6 @@ CUSBHardwareDevice::SetPortFeature(
KeStallExecutionProcessor(100);
}while(TRUE);
//
// delay is 10 ms
//
Timeout.QuadPart = 10;
DPRINT1("Waiting %d milliseconds for port to recover after reset\n", Timeout.LowPart);
//
// convert to 100 ns units (absolute)
//
Timeout.QuadPart *= -10000;
//
// perform the wait
//
KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
//
// is there a status change callback
//
if (m_SCECallBack != NULL)
{
//
// issue callback
//
m_SCECallBack(m_SCEContext);
}
return STATUS_SUCCESS;
}
return STATUS_SUCCESS;
@ -1552,6 +1525,7 @@ InterruptServiceRoutine(
//
// disable interrupt as it will fire untill the port has been reset
//
DPRINT1("Disabling status change interrupt\n");
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_DISABLE_OFFSET), OHCI_ROOT_HUB_STATUS_CHANGE);
Acknowledge |= OHCI_ROOT_HUB_STATUS_CHANGE;
}
@ -1653,6 +1627,18 @@ OhciDefferedRoutine(
//
QueueSCEWorkItem = TRUE;
}
else if (PortStatus & OHCI_RH_PORTSTATUS_PRSC)
{
//
// This is a port reset complete interrupt
//
DPRINT1("Port %d completed reset\n", Index);
//
// Queue a work item
//
QueueSCEWorkItem = TRUE;
}
}
//