[USBEHCI]

- Fix initialization bugs for EHCI controllers
- Try again to release ownership of low-speed devices after reset
- Wait for the port reset to complete

svn path=/branches/usb-bringup-trunk/; revision=55232
This commit is contained in:
Cameron Gutman 2012-01-27 06:27:12 +00:00
parent 9b540bf8a8
commit 6f54b01f29

View file

@ -525,39 +525,10 @@ CUSBHardwareDevice::StartController(void)
StopController(); StopController();
// //
// Reset the device. Bit is set to 0 on completion. // Enable Interrupts and start execution
// //
GetCommandRegister(&UsbCmd); EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
UsbCmd.HCReset = TRUE; /*| EHCI_USBINTR_FLROVR*/ | EHCI_USBINTR_PC);
SetCommandRegister(&UsbCmd);
//
// Check that the controller reset
//
for (FailSafe = 100; FailSafe > 1; FailSafe--)
{
KeStallExecutionProcessor(10);
GetCommandRegister(&UsbCmd);
if (!UsbCmd.HCReset)
{
break;
}
}
//
// If the controller did not reset then fail
//
if (UsbCmd.HCReset)
{
DPRINT1("EHCI ERROR: Controller failed to reset. Hardware problem!\n");
return STATUS_UNSUCCESSFUL;
}
//
// Disable Interrupts and clear status
//
EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, 0);
EHCI_WRITE_REGISTER_ULONG(EHCI_USBSTS, 0x0000001f);
// //
// Assign the AsyncList Register // Assign the AsyncList Register
@ -574,18 +545,10 @@ CUSBHardwareDevice::StartController(void)
// //
GetCommandRegister(&UsbCmd); GetCommandRegister(&UsbCmd);
UsbCmd.PeriodicEnable = TRUE; UsbCmd.PeriodicEnable = TRUE;
UsbCmd.AsyncEnable = TRUE; //FIXME: Need USB Memory Manager
UsbCmd.IntThreshold = 1; UsbCmd.IntThreshold = 1;
// FIXME: Set framelistsize when periodic is implemented.
SetCommandRegister(&UsbCmd); SetCommandRegister(&UsbCmd);
// GetCommandRegister(&UsbCmd);
// Enable Interrupts and start execution
//
EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
/*| EHCI_USBINTR_FLROVR*/ | EHCI_USBINTR_PC);
UsbCmd.Run = TRUE; UsbCmd.Run = TRUE;
SetCommandRegister(&UsbCmd); SetCommandRegister(&UsbCmd);
@ -614,6 +577,14 @@ CUSBHardwareDevice::StartController(void)
// //
EHCI_WRITE_REGISTER_ULONG(EHCI_CONFIGFLAG, 1); EHCI_WRITE_REGISTER_ULONG(EHCI_CONFIGFLAG, 1);
//
// Enable async
//
GetCommandRegister(&UsbCmd);
UsbCmd.AsyncEnable = TRUE; //FIXME: Need USB Memory Manager
// FIXME: Set framelistsize when periodic is implemented.
SetCommandRegister(&UsbCmd);
DPRINT1("EHCI Started!\n"); DPRINT1("EHCI Started!\n");
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -669,6 +640,9 @@ CUSBHardwareDevice::ResetPort(
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex)); PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
//
// check slow speed line before reset
//
if (PortStatus & EHCI_PRT_SLOWSPEEDLINE) if (PortStatus & EHCI_PRT_SLOWSPEEDLINE)
{ {
DPRINT1("Non HighSpeed device. Releasing Ownership\n"); DPRINT1("Non HighSpeed device. Releasing Ownership\n");
@ -676,6 +650,8 @@ CUSBHardwareDevice::ResetPort(
return STATUS_DEVICE_NOT_CONNECTED; return STATUS_DEVICE_NOT_CONNECTED;
} }
ASSERT(PortStatus & EHCI_PRT_CONNECTED);
// //
// Reset and clean enable // Reset and clean enable
// //
@ -692,18 +668,36 @@ CUSBHardwareDevice::ResetPort(
PortStatus &= ~EHCI_PRT_RESET; PortStatus &= ~EHCI_PRT_RESET;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), PortStatus); EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), PortStatus);
KeStallExecutionProcessor(100); do
{
//
// wait
//
KeStallExecutionProcessor(100);
//
// Check that the port reset
//
PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
if (!(PortStatus & EHCI_PRT_RESET))
break;
} while (TRUE);
// //
// Check that the port reset // check slow speed line after reset
// //
PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex)); if (PortStatus & EHCI_PRT_SLOWSPEEDLINE)
if (PortStatus & EHCI_PRT_RESET)
{ {
DPRINT1("Port did not reset\n"); DPRINT1("Non HighSpeed device. Releasing Ownership\n");
return STATUS_RETRY; EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), EHCI_PRT_RELEASEOWNERSHIP);
return STATUS_DEVICE_NOT_CONNECTED;
} }
//
// this must be enabled now
//
ASSERT(PortStatus & EHCI_PRT_ENABLED);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -739,16 +733,18 @@ CUSBHardwareDevice::GetPortStatus(
} }
} }
// Get Speed. If SlowSpeedLine flag is there then its a slow speed device
if (Value & EHCI_PRT_SLOWSPEEDLINE)
Status |= USB_PORT_STATUS_LOW_SPEED;
else
Status |= USB_PORT_STATUS_HIGH_SPEED;
// Get Connected Status // Get Connected Status
if (Value & EHCI_PRT_CONNECTED) if (Value & EHCI_PRT_CONNECTED)
{
Status |= USB_PORT_STATUS_CONNECT; Status |= USB_PORT_STATUS_CONNECT;
// Get Speed. If SlowSpeedLine flag is there then its a slow speed device
if (Value & EHCI_PRT_SLOWSPEEDLINE)
Status |= USB_PORT_STATUS_LOW_SPEED;
else
Status |= USB_PORT_STATUS_HIGH_SPEED;
}
// Get Enabled Status // Get Enabled Status
if (Value & EHCI_PRT_ENABLED) if (Value & EHCI_PRT_ENABLED)
Status |= USB_PORT_STATUS_ENABLE; Status |= USB_PORT_STATUS_ENABLE;
@ -795,30 +791,17 @@ CUSBHardwareDevice::ClearPortStatus(
if (PortId > m_Capabilities.HCSParams.PortCount) if (PortId > m_Capabilities.HCSParams.PortCount)
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
if (Status == C_PORT_RESET) if (Status == C_PORT_RESET)
{ {
if (Value & EHCI_PRT_RESET)
{
Value &= ~EHCI_PRT_RESET;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
KeStallExecutionProcessor(100);
}
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
// //
// update port status // update port status
// //
m_ResetInProgress[PortId] = FALSE; m_ResetInProgress[PortId] = FALSE;
if (!(Value & EHCI_PRT_ENABLED))
{
DPRINT1("Port is not enabled.\n");
}
} }
if (Status == C_PORT_CONNECTION) if (Status == C_PORT_CONNECTION)
{ {
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
Value |= EHCI_PRT_CONNECTSTATUSCHANGE | EHCI_PRT_ENABLEDSTATUSCHANGE; Value |= EHCI_PRT_CONNECTSTATUSCHANGE | EHCI_PRT_ENABLEDSTATUSCHANGE;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value); EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
} }
@ -851,11 +834,6 @@ CUSBHardwareDevice::SetPortFeature(
if (Feature == PORT_RESET) if (Feature == PORT_RESET)
{ {
if (Value & EHCI_PRT_SLOWSPEEDLINE)
{
DPRINT1("Non HighSpeed device. Releasing Ownership\n");
}
ResetPort(PortId); ResetPort(PortId);
// //