I am having problems with my EHCI driver. It for the most part seems to works fine (and has for the last year). Lately, I have been working with larger files (100s of kilobytes instead of just a few). The EHCI driver does a thousand or so transactions (it varies greatly), and then freezes on the wait for USB interrupt. I have included the file below with the driver. The method I am talking about is PerformTransactions(). I have deleted some methods I believe not to be causing the problems. I have tried adding delays into performing transactions but that doesn't help. I added a really rough timeout in the method and scaled it back. The timeout resets the port, reconfigures it and continues on as if nothing happened. The problem arises when it continues loading the file. It is able to do the 19 configuration transactions (including some on the bulk endpoint) perfectly. It only fails when it is back to parsing the file.
Code: Select all
#include "EHCIPrivate.h"
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;
EHCI::Private::EnableInterrupts();
EHCI::Private::OpRegister->PERIODICLISTBASE = 0;
//EHCI::Private::OpRegister->USBCMD.InterruptThresholdControl = 8;
EHCI::Private::OpRegister->ASYNCLISTADDR = 0;
EHCI::Private::OpRegister->USBCMD.RunStop = 1;
while (EHCI::Private::OpRegister->USBSTS.HCHalted == 1)
{
PIT::WaitMilliseconds(20);
}
EHCI::Private::OpRegister->CONFIGFLAG.ConfigureFlag = 1;
PIT::WaitMilliseconds(50);
}
void EHCI::Private::EHCIIRQHandler()
{
_asm add esp, 12;
_asm pushad;
_asm sti;
if (EHCI::Private::OpRegister->USBSTS.USBINT)
{
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)
{
EHCI::Private::OpRegister->USBSTS.PortChangeDetect = 1;
OutPort(0xA0, 0x20);
OutPort(0x20, 0x20);
PIT::WaitMilliseconds(30);
EHCI::Private::ResetPorts();
_asm popad;
_asm iretd;
}
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 cli;
_asm hlt;
}
if (EHCI::Private::OpRegister->USBSTS.InterruptOnAsyncAdvance)
{
Video::Print("\nInterrupt on Async Advance\n");
EHCI::Private::OpRegister->USBSTS.InterruptOnAsyncAdvance = 1;
}
OutPort(0xA0, 0x20);
OutPort(0x20, 0x20);
_asm popad;
_asm iretd;
}
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)
{
dword tempINTR = 0;
memcpy(&tempINTR, (void*)&EHCI::Private::OpRegister->USBINTR, sizeof(EHCI::Private::OpRegister->USBINTR));
port->PortReset = 1;
PIT::WaitMilliseconds(300);
port->PortReset = 0;
while (port->PortReset == 1)
{
PIT::WaitMilliseconds(20);
}
memcpy((void*)&EHCI::Private::OpRegister->USBINTR, &tempINTR, sizeof(EHCI::Private::OpRegister->USBINTR));
}
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)
{
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;
}
}
}
}
static volatile int CoolDown = 0;
void EHCI::Private::PerformTransaction(dword AsyncAddress, bool wait, byte port)
{
dword timeout = 100;
timeout = 100;
EHCI::Private::USBInterrupt = false;
EHCI::Private::OpRegister->ASYNCLISTADDR = VirtualMemory::PhysicalAddress(AsyncAddress);
EHCI::Private::OpRegister->USBCMD.AsynchronousScheduleEnable = 1;
//while (EHCI::Private::OpRegister->USBSTS.AsynchronousScheduleStatus == 0)
//{
//PIT::WaitMilliseconds(5); // 5
//}
if (wait)
PIT::WaitMilliseconds(50);
else
{
}
_asm hlt;
Video::Print(" a ");
while (!EHCI::Private::USBInterrupt)
{
PIT::WaitMilliseconds(10); // 5
timeout--;
if (timeout <= 1 && !wait)
{
Video::Print(" ehci ");
EHCI::ResetPort(port);
USB20::DeConfigureDevice(EHCI::Private::PortConnectStatus[port]);
EHCI::Private::PortConnectStatus[port] = 0;
EHCI::Private::PortConnectStatus[port] = USB20::ConfigureDevice(port);
EHCI::Private::OpRegister->USBSTS.USBINT = 1;
EHCI::Private::USBInterrupt = false;
PIT::WaitMilliseconds(300);
timeout = 100;
EHCI::Private::PerformTransaction(AsyncAddress, wait, port);
return;
break;
}
}
EHCI::Private::USBInterrupt = false;
//EHCI::Private::OpRegister->USBCMD.AsynchronousScheduleEnable = 0;
//while (EHCI::Private::OpRegister->USBSTS.AsynchronousScheduleStatus == 1)
//{
//PIT::WaitMilliseconds(10); //5
//_asm hlt;
//}
//EHCI::Private::OpRegister->USBCMD.AsynchronousScheduleEnable = 0;
CoolDown++;
Video::PrintNumber(CoolDown, 10);Video::Print(" ");
return;
}
EHCI::Private::QTD* EHCI::Private::AllocateQTD(dword next)
{
EHCI::Private::QTD* qtd = (EHCI::Private::QTD*)Heap::Malloc(sizeof(EHCI::Private::QTD), 32);
memset(qtd, 0, sizeof(EHCI::Private::QTD));
if (next == 0)
qtd->NextQTDPointer = 1;
else
qtd->NextQTDPointer = VirtualMemory::PhysicalAddress(next);
return qtd;
}
dword EHCI::Private::AllocateQTDBuffer(EHCI::Private::QTD* qtd)
{
void* data = Heap::Malloc(4096, 4096);
memset(data, 0, 4096);
qtd->BufferPointer0 = VirtualMemory::PhysicalAddress((dword)data);
qtd->BufferPointer1 = qtd->BufferPointer2 = qtd->BufferPointer3 = qtd->BufferPointer4 = 0;
return (dword)data;
}
void EHCI::Private::CreateQueueHead(void* QHAddr, dword HorizontalPointer, void* FirstQTD, byte DeviceAddr, byte EndpointNum, dword MaxPacketSize)
{
EHCI::Private::QueueHead* qh = (EHCI::Private::QueueHead*)QHAddr;
memset(QHAddr, 0, sizeof(EHCI::Private::QueueHead));
qh->HorizontalPointer = VirtualMemory::PhysicalAddress(HorizontalPointer) | 2;
qh->DeviceAddress = DeviceAddr;
qh->InactivateOnNextTransaction = 0;
qh->EndpointNumber = EndpointNum;
qh->EndpointSpeed = 2;
qh->DTC = 1;
qh->H = 1;
qh->MaximumPacketLength = MaxPacketSize;
qh->ControlEndpointFlag = 0;
qh->NakReloadFlag = 15;
qh->SMask = 0;
qh->CMask = 0;
qh->HubAddr = 0;
qh->PortNumber = 0;
qh->Mult = 1;
if (FirstQTD == 0)
{
qh->QTD.NextQTDPointer = 1;
}
else
{
qh->QTD.NextQTDPointer = VirtualMemory::PhysicalAddress((dword)FirstQTD);
}
}
void* EHCI::Private::CreateSetupQTD(dword next, bool toggle, dword tokenBytes, dword type, dword requestID, dword valueLo, dword valueHi, dword index, dword length, dword* buff)
{
byte SETUP = 2;
EHCI::Private::QTD* qtd = EHCI::Private::AllocateQTD(next);
qtd->AlternateNextQTDPointer = 1;
qtd->Token.Status = 0x80;
qtd->Token.PIDCode = 2;
qtd->Token.ErrorCounter = 3;
qtd->Token.CurrentPage = 0;
qtd->Token.InterruptOnComplete = 1;
qtd->Token.TotalBytestoTransfer = tokenBytes;
qtd->Token.DataToggle = toggle;
dword buffer = EHCI::Private::AllocateQTDBuffer(qtd);
EHCI::Private::SetupData* request = (EHCI::Private::SetupData*)buffer;
request->RequestType = type;
request->RequestID = requestID;
request->ValueHi = valueHi;
request->ValueLow = valueLo;
request->Index = index;
request->Length = length;
*buff = buffer;
return (void*)qtd;
}
void* EHCI::Private::CreateIOQTD(dword next, byte direction, bool toggle, dword tokenBytes, dword *buff)
{
byte OUT = 0;
byte IN = 1;
EHCI::Private::QTD* qtd = EHCI::Private::AllocateQTD(next);
qtd->AlternateNextQTDPointer = 1;
qtd->Token.Status = 0x80;
qtd->Token.PIDCode = direction;
qtd->Token.ErrorCounter = 3;
qtd->Token.CurrentPage = 0;
qtd->Token.InterruptOnComplete = 1;
qtd->Token.TotalBytestoTransfer = tokenBytes;
qtd->Token.DataToggle = toggle;
dword buffer = EHCI::Private::AllocateQTDBuffer(qtd);
*buff = buffer;
return (void*)qtd;
}
byte EHCI::SetupTransaction(byte DevAddr, byte EndpointNum, word BytesToTransfer, byte RequestType, byte Request, byte ValueHi, byte ValueLow, word Index, byte* Data, byte direction, byte port)
{
byte OUT = 0;
byte IN = 1;
byte SETUP = 2;
void* virtAList = Heap::Malloc(sizeof(EHCI::Private::QueueHead), 32);
EHCI::Private::OpRegister->USBCMD.AsynchronousScheduleEnable = 0;
dword SetupBuffer = 0;
dword DataBuffer = 0;
if (BytesToTransfer == 0)
{
void* HandShakeQTD = 0;
HandShakeQTD = EHCI::Private::CreateIOQTD(0, IN, 1, 0, &DataBuffer);
Heap::Free((void*)DataBuffer);
void* SetupQTD = EHCI::Private::CreateSetupQTD((dword)HandShakeQTD, 0, 8, RequestType, Request, ValueLow, ValueHi, Index, 0, &SetupBuffer);
EHCI::Private::CreateQueueHead(virtAList, (dword)virtAList, SetupQTD, DevAddr, EndpointNum, 64);
EHCI::Private::PerformTransaction((dword)virtAList, true, port);
if ((((EHCI::Private::QTD*)SetupQTD)->Token.Status) != 0)
{
Video::Print("\nQTD Status: ");
Video::PrintNumber(((EHCI::Private::QTD*)SetupQTD)->Token.Status, 10);
Video::NewLine();
}
if (((EHCI::Private::QTD*)SetupQTD)->Token.Status != 0)
{
Video::Print("\nTransaction Error!!\n");
Heap::Free((void*)SetupBuffer);
Heap::Free((void*)virtAList);
Heap::Free((void*)HandShakeQTD);
Heap::Free((void*)SetupQTD);
return 0;
}
Heap::Free((void*)SetupBuffer);
Heap::Free((void*)virtAList);
Heap::Free((void*)HandShakeQTD);
Heap::Free((void*)SetupQTD);
return 1;
}
void* HandShakeQTD = 0;
if (direction == IN)
{
HandShakeQTD = EHCI::Private::CreateIOQTD(0, OUT, 1, 0, &DataBuffer);
}
else
{
HandShakeQTD = EHCI::Private::CreateIOQTD(0, IN, 1, 0, &DataBuffer);
}
Heap::Free((void*)DataBuffer);
void* DataQTD = EHCI::Private::CreateIOQTD((dword)HandShakeQTD, direction, 1, BytesToTransfer, &DataBuffer);
if (direction == OUT)
{
memcpy((void*)DataBuffer, Data, BytesToTransfer);
}
void* SetupQTD = EHCI::Private::CreateSetupQTD((dword)DataQTD, 0, 8, RequestType, Request, ValueLow, ValueHi, Index, BytesToTransfer, &SetupBuffer);
EHCI::Private::CreateQueueHead(virtAList, (dword)virtAList, SetupQTD, DevAddr, EndpointNum, 64);
EHCI::Private::PerformTransaction((dword)virtAList, true, port);
if (direction == IN)
{
memcpy(Data, (void*)DataBuffer, BytesToTransfer);
}
if ((((EHCI::Private::QTD*)SetupQTD)->Token.Status) != 0)
{
Video::Print("\nQTD Status: ");
Video::PrintNumber(((EHCI::Private::QTD*)SetupQTD)->Token.Status, 10);
Video::NewLine();
}
if (((EHCI::Private::QTD*)SetupQTD)->Token.Status != 0)
{
Video::Print("\nTransaction Error!!\n");
Heap::Free((void*)SetupBuffer);
Heap::Free((void*)DataBuffer);
Heap::Free((void*)virtAList);
Heap::Free((void*)HandShakeQTD);
Heap::Free((void*)DataQTD);
Heap::Free((void*)SetupQTD);
return 0;
}
Heap::Free((void*)SetupBuffer);
Heap::Free((void*)DataBuffer);
Heap::Free((void*)virtAList);
Heap::Free((void*)HandShakeQTD);
Heap::Free((void*)DataQTD);
Heap::Free((void*)SetupQTD);
return 1;
}
byte EHCI::BulkTransaction(byte DevAddr, byte EndpointNum, word BytesToTransfer, byte* data, byte direction, byte port, byte toggle, word MaxPacketSize)
{
Retry:
byte OUT = 0;
byte IN = 1;
void* virtAList = Heap::Malloc(sizeof(EHCI::Private::QueueHead), 32);
//EHCI::Private::OpRegister->USBCMD.AsynchronousScheduleEnable = 0;
dword DataBuffer = 0;
void* DataQTD = EHCI::Private::CreateIOQTD(1, direction, toggle, BytesToTransfer, &DataBuffer);
if (direction == OUT)
{
memcpy((void*)DataBuffer, data, BytesToTransfer);
}
EHCI::Private::CreateQueueHead(virtAList, (dword)virtAList, DataQTD, DevAddr, EndpointNum, MaxPacketSize);
EHCI::Private::PerformTransaction((dword)virtAList, false, port);
if (direction == IN)
{
memcpy(data, (void*)DataBuffer, BytesToTransfer);
}
Heap::Free((void*)DataBuffer);
Heap::Free((void*)virtAList);
Heap::Free((void*)DataQTD);
return 1;
}
byte EHCI::MSDBulkSCSIRead(byte DevAddr, byte EndpointNumOut, byte EndpointNumIn, byte port, bool toggleIN, bool toggleOUT, word MaxPacketSize, byte* cbw, byte* data, byte* status)
{
Retry:
byte OUT = 0;
byte IN = 1;
void* virtAList = Heap::Malloc(sizeof(EHCI::Private::QueueHead), 32);
void* virtAList2 = Heap::Malloc(sizeof(EHCI::Private::QueueHead), 32);
//EHCI::Private::OpRegister->USBCMD.AsynchronousScheduleEnable = 0;
dword DataBufferCBW = 0;
dword DataBufferData = 0;
dword StatusBuffer = 0;
void* StatusQtd = EHCI::Private::CreateIOQTD(1, IN, !toggleIN, 13, &StatusBuffer);
void* DataQtd = EHCI::Private::CreateIOQTD((dword)StatusQtd, IN, toggleIN, 512, &DataBufferData);
void* CBWQtd = EHCI::Private::CreateIOQTD(1, OUT, toggleOUT, 31, &DataBufferCBW);
memcpy((void*)DataBufferCBW, cbw, 31);
EHCI::Private::CreateQueueHead(virtAList, (dword)virtAList, CBWQtd, DevAddr, EndpointNumOut, MaxPacketSize);
EHCI::Private::CreateQueueHead(virtAList2, (dword)virtAList2, DataQtd, DevAddr, EndpointNumIn, MaxPacketSize);
EHCI::Private::PerformTransaction((dword)virtAList, false, port);
EHCI::Private::PerformTransaction((dword)virtAList2, false, port);
memcpy(data, (void*)DataBufferData, 512);
memcpy(status, (void*)StatusBuffer, 13);
Heap::Free((void*)virtAList);
Heap::Free((void*)virtAList2);
Heap::Free((void*)DataBufferCBW);
Heap::Free((void*)DataBufferData);
Heap::Free((void*)StatusBuffer);
Heap::Free((void*)StatusQtd);
Heap::Free((void*)DataQtd);
Heap::Free((void*)CBWQtd);
return 1;
}
Hoozim