I wrote an EHCI driver a number of years ago that works just fine with a 10 year old computer and VirtualBox, but not on my 6 month old netbook. This netbook contains two EHCI controllers (each with their own OHCI companion). One pair handles the USB ports the other the SD card reader. There is also a single XHCI port which I am not using. When I reset the controller and start it, I often get an EHCI interrupt with a zero USBSTS or a frame list rollover. I have the frame list rollover interrupt turned off. After that, I never receive any EHCI interrupts. Why is it that I don't receive any interrupts? My interrupt handler sends the EOI bytes and does the IRET stuff.
Here is the code:
Code: Select all
void EHCI::ConfigureEHCI(dword baseAddressPhysical, byte interrupt)
{
/*static bool configonce = true;
if (configonce == true)
{
configonce = false;
return;
}*/
EHCI::Private::BaseAddressPhysical = baseAddressPhysical;
EHCI::Private::Interrupt = interrupt;
dword baseAddress = (dword)VirtualMemory::PCIMemory(baseAddressPhysical, 1);
EHCI::Private::BaseAddress = baseAddress;
EHCI::Private::CapabilityRegisters* capRegs = (EHCI::Private::CapabilityRegisters*)baseAddress;
EHCI::Private::CapRegister = capRegs;
EHCI::Private::NumberOfPorts = capRegs->HCSPARAMS.N_PORTS;
if (capRegs->HCCPARAMS.Addressing64Bit)
{
EHCI::Private::Addressing64Bit = 1;
//return; Virtual Box Uses a 64 Bit EHCI
}
if (capRegs->HCSPARAMS.PortPowerControl)
{
EHCI::Private::PortPowerControl = 1;
}
EHCI::Private::OperationalRegistersBase = EHCI::Private::BaseAddress + capRegs->CAPLENGTH;
EHCI::Private::OperationalRegisters* opRegs = (EHCI::Private::OperationalRegisters*)EHCI::Private::OperationalRegistersBase;
EHCI::Private::OpRegister = (EHCI::Private::OperationalRegisters*)EHCI::Private::OperationalRegistersBase;
EHCI::Private::PORTSCBaseAddress = ((EHCI::Private::OperationalRegistersBase) + 0x44);
Video::PrintNumber(EHCI::Private::NumberOfPorts, 16);
IDT::InstallIRQ(32 + interrupt, &EHCI::Private::EHCIIRQHandler);
USB20::ConfigureUSB20();
EHCI::Private::ResetEHCI();
for (int i = 0; i < EHCI::Private::NumberOfPorts; i++)
{
EHCI::Private::PORTSC* port = EHCI::Private::SelectPortSC(i);
if (EHCI::Private::PortPowerControl)
{
port->PortPower = 1;
}
}
rerun:
for (byte j = 0; j < EHCI::Private::NumberOfPorts; j ++)
{
EHCI::Private::PORTSC* port = EHCI::Private::SelectPortSC(j);
port->PortPower = 1;
port->PortEnabled = 0;
EHCI::Private::OpRegister->USBSTS.PortChangeDetect = 0;
if (EHCI::Private::OpRegister->USBSTS.HCHalted)
{
Video::Print("Error: hchalted");
for(;;);
}
EHCI::Private::ResetPort(port);
Video::PrintNumber(port->PortEnabled, 10);Video::NewLine();
if (port->PortEnabled)
USB20::ConfigureDevice(j);
}
}
void EHCI::Private::ResetEHCI()
{
EHCI::Private::OpRegister->USBCMD.RunStop = 0;
while (EHCI::Private::OpRegister->USBSTS.HCHalted == 0)
{
PIT::WaitMilliseconds(30);
}
EHCI::Private::OpRegister->USBCMD.HostControllerReset = 1;
while (EHCI::Private::OpRegister->USBCMD.HostControllerReset == 1)
{
PIT::WaitMilliseconds(20);
}
EHCI::Private::OpRegister->CTRLDSSEGMENT = 0;
memset((void*)&EHCI::Private::OpRegister->USBSTS, 0, sizeof(EHCI::Private::OperationalRegisters::USBSTS));
EHCI::Private::EnableInterrupts();
EHCI::Private::OpRegister->PERIODICLISTBASE = 0;
EHCI::Private::OpRegister->USBCMD.InterruptThresholdControl = 8;
EHCI::Private::OpRegister->ASYNCLISTADDR = 0;
Video::Print("standby");
Keyboard::WaitForKeyDown();
EHCI::Private::OpRegister->USBCMD.RunStop = 1;
while (EHCI::Private::OpRegister->USBSTS.HCHalted == 1)
{
PIT::WaitMilliseconds(20);
}
Video::Print("Reset");
Keyboard::WaitForKeyDown();
Video::Print("pro");
Keyboard::WaitForKeyDown();
EHCI::Private::OpRegister->CONFIGFLAG.ConfigureFlag = 1;
Video::Print("seed");
Keyboard::WaitForKeyDown();
Video::Print("on");
PIT::WaitMilliseconds(50);
}
void EHCI::Private::EnableInterrupts()
{
EHCI::Private::OpRegister->USBINTR.HostSystemErrorEnable = 1;
EHCI::Private::OpRegister->USBINTR.InterruptOnAsyncAdvanceEnable = 1;
EHCI::Private::OpRegister->USBINTR.PortChangeInterruptEnable = 1;
EHCI::Private::OpRegister->USBINTR.USBErrorInterruptEnable = 1;
EHCI::Private::OpRegister->USBINTR.USBInterruptEnable = 1;
}
void EHCI::Private::DisableInterrupts()
{
EHCI::Private::OpRegister->USBINTR.HostSystemErrorEnable = 0;
EHCI::Private::OpRegister->USBINTR.InterruptOnAsyncAdvanceEnable = 0;
EHCI::Private::OpRegister->USBINTR.PortChangeInterruptEnable = 0;
EHCI::Private::OpRegister->USBINTR.USBErrorInterruptEnable = 0;
EHCI::Private::OpRegister->USBINTR.USBInterruptEnable = 0;
}
void EHCI::Private::EHCIIRQHandler(IDT::Registers* r)
{
standby:
dword usbsts = 0;
memcpy ((void*)&usbsts, (void*)&EHCI::Private::OpRegister->USBSTS, 4);
Video::NewLine();Video::PrintNumber(usbsts, 16);Video::NewLine();
if (usbsts == 0)
{
goto standby;
}
Video::Print("ehciinterrupt\n");
if (EHCI::Private::OpRegister->USBSTS.USBINT)
{
Video::Print("\nintr\n");
EHCI::Private::USBInterrupt = true;
EHCI::Private::OpRegister->USBSTS.USBINT = 1;
}
if (EHCI::Private::OpRegister->USBSTS.USBERRINT)
{
Video::Print("\nUSB Error Interrupt\n");
EHCI::Private::OpRegister->USBSTS.USBERRINT = 1;
}
if (EHCI::Private::OpRegister->USBSTS.PortChangeDetect)
{
Video::Print("port change");
EHCI::Private::OpRegister->USBSTS.PortChangeDetect = 1;
OutPort(0xA0, 0x20);
OutPort(0x20, 0x20);
//_asm sti;
asm volatile("sti");
PIT::WaitMilliseconds(30);
EHCI::Private::ResetPorts();
}
if (EHCI::Private::OpRegister->USBSTS.FrameListRollover)
{
Video::Print("\nFrame List Rollover\n");
EHCI::Private::OpRegister->USBSTS.FrameListRollover = 1;
}
if (EHCI::Private::OpRegister->USBSTS.HostSystemError)
{
Video::Print("\nHost System Error\n");
Video::Print("Halting system...");
EHCI::Private::OpRegister->USBSTS.HostSystemError = 1;
asm volatile("cli");
asm volatile("hlt");
}
if (EHCI::Private::OpRegister->USBSTS.InterruptOnAsyncAdvance)
{
Video::Print("\nInterrupt on Async Advance\n");
EHCI::Private::OpRegister->USBSTS.InterruptOnAsyncAdvance = 1;
}
}
EHCI::Private::PORTSC* EHCI::Private::SelectPortSC(byte port)
{
dword* NewAddress = (dword*)(EHCI::Private::PORTSCBaseAddress + (port * 4));
return (EHCI::Private::PORTSC*)NewAddress;
}
void EHCI::Private::ResetPort(EHCI::Private::PORTSC* port)
{
EHCI::Private::DisableInterrupts();
port->PortReset = 1;
PIT::WaitMilliseconds(300);
port->PortReset = 0;
while (port->PortReset == 1)
{
PIT::WaitMilliseconds(20);
}
EHCI::Private::EnableInterrupts();
}
void EHCI::ResetPort(byte i)
{
EHCI::Private::PORTSC* port = EHCI::Private::SelectPortSC(i);
EHCI::Private::ResetPort(port);
}
void EHCI::Private::ResetPorts()
{
for (int i = 0; i < EHCI::Private::NumberOfPorts; i++)
{
EHCI::Private::PORTSC* port = EHCI::Private::SelectPortSC(i);
if (port->CurrentConnectStatus)
{
Video::PrintNumber(i, 10);Video::NewLine();
if (EHCI::Private::PortConnectStatus[i] == 0)
{
EHCI::Private::ResetPort(port);
EHCI::Private::PortConnectStatus[i] = USB20::ConfigureDevice(i);
}
}
else
{
if (EHCI::Private::PortConnectStatus[i] != 0)
{
USB20::DeConfigureDevice(EHCI::Private::PortConnectStatus[i]);
EHCI::Private::PortConnectStatus[i] = 0;
}
}
}
}
Jacob