[USBEHCI]

- More EHCI reset fixes and general code cleanup

svn path=/trunk/; revision=55850
This commit is contained in:
Cameron Gutman 2012-02-25 04:27:39 +00:00
parent 7d6c0c114c
commit 7991e67594

View file

@ -958,16 +958,7 @@ CUSBHardwareDevice::ResetPort(
PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex)); PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
// ASSERT(!(PortStatus & EHCI_PRT_SLOWSPEEDLINE));
// check slow speed line before reset
//
if (PortStatus & EHCI_PRT_SLOWSPEEDLINE)
{
DPRINT1("Non HighSpeed device. Releasing Ownership\n");
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), PortStatus | EHCI_PRT_RELEASEOWNERSHIP);
return STATUS_DEVICE_NOT_CONNECTED;
}
ASSERT(PortStatus & EHCI_PRT_CONNECTED); ASSERT(PortStatus & EHCI_PRT_CONNECTED);
// //
@ -1033,11 +1024,8 @@ CUSBHardwareDevice::GetPortStatus(
{ {
Status |= USB_PORT_STATUS_CONNECT; Status |= USB_PORT_STATUS_CONNECT;
// Get Speed. If SlowSpeedLine flag is there then its a slow speed device // EHCI only supports high speed
if (Value & EHCI_PRT_SLOWSPEEDLINE) Status |= USB_PORT_STATUS_HIGH_SPEED;
Status |= USB_PORT_STATUS_LOW_SPEED;
else
Status |= USB_PORT_STATUS_HIGH_SPEED;
} }
// Get Enabled Status // Get Enabled Status
@ -1078,7 +1066,7 @@ CUSBHardwareDevice::ClearPortStatus(
ULONG PortId, ULONG PortId,
ULONG Status) ULONG Status)
{ {
ULONG Value, WaitTime, ResetComplete; ULONG Value;
LARGE_INTEGER Timeout; LARGE_INTEGER Timeout;
DPRINT("CUSBHardwareDevice::ClearPortStatus PortId %x Feature %x\n", PortId, Status); DPRINT("CUSBHardwareDevice::ClearPortStatus PortId %x Feature %x\n", PortId, Status);
@ -1088,41 +1076,27 @@ CUSBHardwareDevice::ClearPortStatus(
if (Status == C_PORT_RESET) if (Status == C_PORT_RESET)
{ {
do // Clear reset
{ Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
// wait for completion Value &= (EHCI_PORTSC_DATAMASK | EHCI_PRT_ENABLED);
ResetComplete = FALSE; Value &= ~EHCI_PRT_RESET;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
// Clear reset
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
Value &= (EHCI_PORTSC_DATAMASK | EHCI_PRT_ENABLED);
Value &= ~EHCI_PRT_RESET;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
for(WaitTime = 0; WaitTime < 500; WaitTime += 20)
{
// wait
KeStallExecutionProcessor(20);
// Check that the port reset
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
// is complete
if (!(Value & EHCI_PRT_RESET))
{
// check for bogus value
if (Value == MAXULONG)
continue;
// reset done
ResetComplete = TRUE;
break;
}
}
} while (!ResetComplete);
// //
// delay is 10 ms // wait for reset bit to clear
//
do
{
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
if (!(Value & EHCI_PRT_RESET))
break;
KeStallExecutionProcessor(20);
} while (TRUE);
//
// delay is 50 ms
// //
Timeout.QuadPart = 50; Timeout.QuadPart = 50;
DPRINT1("Waiting %d milliseconds for port to recover after reset\n", Timeout.LowPart); DPRINT1("Waiting %d milliseconds for port to recover after reset\n", Timeout.LowPart);
@ -1138,34 +1112,26 @@ CUSBHardwareDevice::ClearPortStatus(
KeDelayExecutionThread(KernelMode, FALSE, &Timeout); KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
// //
// check slow speed line after reset // check the enabled bit after reset
// //
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId)); Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
if (!(Value & EHCI_PRT_CONNECTED))
// did the reset complete successfully
if (Value != MAXULONG)
{ {
if (Value & EHCI_PRT_ENABLED || !(Value & EHCI_PRT_CONNECTED) || Value & EHCI_PRT_CONNECTSTATUSCHANGE) DPRINT1("No device is here after reset. Bad controller/device?\n");
{ return STATUS_UNSUCCESSFUL;
// successfully reset port }
DPRINT1("Port is back up after reset\n"); else if (!(Value & EHCI_PRT_ENABLED))
return STATUS_SUCCESS; {
} // release ownership
DPRINT1("Full speed device connected. Releasing ownership\n");
// either the port failed to reset
// or it is a full speed / low speed device
// release control to companion controller
DPRINT("[USBEHCI] Failed to reset port Id %x PortStatus %x releasing ownership\n", PortId, Value);
// re-read register
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
// releaseing ownership
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value | EHCI_PRT_RELEASEOWNERSHIP); EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value | EHCI_PRT_RELEASEOWNERSHIP);
return STATUS_DEVICE_NOT_CONNECTED; return STATUS_DEVICE_NOT_CONNECTED;
} }
else
{
DPRINT1("High speed device connected\n");
return STATUS_SUCCESS;
}
} }
else if (Status == C_PORT_CONNECTION) else if (Status == C_PORT_CONNECTION)
{ {
@ -1498,7 +1464,7 @@ EhciDefferedRoutine(
if (PortStatus & EHCI_PRT_SLOWSPEEDLINE) if (PortStatus & EHCI_PRT_SLOWSPEEDLINE)
{ {
DPRINT1("Non HighSpeed device connected. Release ownership\n"); DPRINT1("Low speed device connected. Releasing ownership\n");
This->EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * i), PortStatus | EHCI_PRT_RELEASEOWNERSHIP); This->EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * i), PortStatus | EHCI_PRT_RELEASEOWNERSHIP);
continue; continue;
} }