USB -- EHCI

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Hoozim
Member
Member
Posts: 53
Joined: Fri Jul 23, 2010 8:26 am

USB -- EHCI

Post by Hoozim »

I am trying to make a test EHCI driver and I am having problems. It is resetting and enabling the ports properly but transactions arent working.

Here is the code. The method I am having problems with is DoTransactions(byte port);

Code: Select all

#include "LoadKernel.h"
#include "Bootinfo.h"
 
#define GetPhysicalAddress(x) (*x & ~0xFFF)
void EHCI();
 
 
void Main(Bootinfo::MultibootInfo* bootinfo, dword kernelsize)
{
    LoadKernel::InitializeSystems(bootinfo, kernelsize);
 
    EHCI();
    Shell::RunShell();
    
    LoadKernel::DeInitializeSystems();
}
 
void Beep(byte on)
{
    OutPort(0x61, on * 163);
}
 
 
 
// /USB Testing -
// /-------------
// /-------------
// /-------------
 
#include "USB.h"
 
dword BaseRegister = 0;
dword OperationalRegisterBase = 0;
byte NumberOfPorts = 0;
dword PortBase = 0;
 
struct CapibilityRegisters
{
    byte CAPLENGTH;
    byte RESERVED;
    word HCIVERSION;
    dword HCSPARAMS;
    dword HCCPARAMS;
    byte HCSPPORTROUTE[8];
};
 
struct OperationRegisters
{
    dword USBCMD;
    dword USBSTS;
    dword USBINTR;
    dword FRINDEX;
    dword CTRLDSSEGMENT;
    dword PERIODICLISTBASE;
    dword ASYNCLISTADDR;
    byte Reserved[36];
    dword CONFIGFLAG;
};
OperationRegisters* op;
 
 
dword ReadPci(byte bus, byte device, byte funct, byte offset)
{
    dword address = (bus << 16) | (device << 11) | (funct << 8) | (offset & 0xFC) | (0x80000000);
    OutPortDWord(0xCF8, address);
    return InPortDWord(0xCFC);
}
 
void DisplayEHCIPCI()
{
    dword classcode = ReadPci(0, 3, 3, 8);
    Video::Print("Class code: ");
    Video::PrintNumber((classcode >> 24) & 0xFF, 16);
    Video::Print(" Sub class code: ");
    Video::PrintNumber((classcode >> 16) & 0xFF, 16);
    Video::Print(" Programming Interface: ");
    Video::PrintNumber((classcode >> 8) & 0xFF, 16);
    Video::Print("\n\n");
}
 
void ReadBaseRegister()
{
    dword base = ReadPci(0, 3, 3, 0x10);
    Video::Print("Base register address: 0x");
    Video::PrintNumber(base, 16);
    Video::Print("  -  ");
    Video::PrintNumber(base, 10);
    VirtualMemory::AllocateRandomPage(true, &BaseRegister);
    VirtualMemory::FreePage(BaseRegister);
    VirtualMemory::MapPage((void*)base, (void*)BaseRegister);
    Video::Print("\n\n");
}
 
void ReadPCIReleaseNumber()
{
    dword num = ReadPci(0, 3, 3, 0x60);
    Video::Print("Serial Bus Release Number: ");
    Video::PrintNumber((byte)num, 16);
    Video::Print("\n\n");
}
 
void CapibilityPortsHCS(dword HCSPARAMS)
{
    byte NOPs = (HCSPARAMS & 0xF);
    Video::Print("\nNOPs: ");
    Video::PrintNumber(NOPs, 10);
    NumberOfPorts = NOPs;
 
    byte DebugPortNumber = (HCSPARAMS & 0xFF000000);
    Video::Print("    Debug Port: ");
    Video::PrintNumber(DebugPortNumber, 10);
 
    byte PortPower = ((HCSPARAMS >> 4) & 1);
    Video::Print("    Port Power: ");
    Video::PrintNumber(PortPower, 10);
}
 
void ParseCapibilityRegisters()
{
    CapibilityRegisters cap = *((CapibilityRegisters*)BaseRegister);
    Video::Print("CAPLENGTH: ");
    Video::PrintNumber(cap.CAPLENGTH, 10);
    OperationalRegisterBase = (BaseRegister + cap.CAPLENGTH);
 
    Video::Print("\nHCIVERSION: ");
    Video::PrintNumber(cap.HCIVERSION, 16);
 
    CapibilityPortsHCS(cap.HCSPARAMS);
    
    Video::Print("\n\n");
}
 
void OperateRegisters()
{
    op = ((OperationRegisters*)OperationalRegisterBase);
    op->USBCMD |= 2;
    while ((op->USBCMD & 2) == 1) {}
 
    op->PERIODICLISTBASE |= 0xFFFFF000;
    op->USBCMD |= 1;
    op->CONFIGFLAG |= 1;
    PIT::WaitMilliseconds(200);
    Video::Print("Host Controller Reset\n\n");
    
    PortBase = OperationalRegisterBase + 0x44;
}
 
dword* SelectPort(byte portnumber)
{
    return (dword*)(PortBase + (portnumber * 4));
}
 
byte Ports()
{
    while (true)
    {
        for (int i = 0; i < NumberOfPorts; i++)
        {
            dword* base = SelectPort(i);
            dword enable = (((*base) >> 0) & 1);
            if (enable)
            {
                Video::Print("Device has been inserted into port: ");
                Video::PrintNumber(i, 10);
 
                Beep(1);
                PIT::WaitMilliseconds(50);
                *base |= 256;
                PIT::WaitMilliseconds(50);
                *base &= ~256;
                PIT::WaitMilliseconds(10);
                Beep(0);
 
                Video::Print(" With data code: ");
                Video::PrintNumber(*base, 10);
                Video::NewLine();
 
                return i;
            }
        }
    }
}
 
void DoTransactions(byte port)
{
    Keyboard::WaitForKeyDown();
    dword qhmem = 0;
    VirtualMemory::AllocateRandomPage(true, &qhmem);
 
    QueueHead* qh = (QueueHead*)qhmem;    
    qh->HorizontalPointer = 0;
    qh->HorizontalPointer |= 2;
    qh->HorizontalPointer |= qhmem;
 
    qh->StaticEndpoint[0] = 0;
    qh->StaticEndpoint[0] |= 0; // DeviceAddress    TO BE FILLED IN!!!
    qh->StaticEndpoint[0] |= 8192; // EndpointSpeed
    qh->StaticEndpoint[0] |= 0x400000; // qMaxPacketSize
    qh->StaticEndpoint[0] |= 0xF0000000; // NakReloader
 
    qh->StaticEndpoint[1] = 0;
    qh->StaticEndpoint[1] |= 0x40000000; // Multiplyer
    qh->CurrentQtd = 0;
    memset(&qh->Overlay, 0, 32);
    qh->Overlay[0] |= 1;
    qh->Overlay[1] |= 1;
 
    op->ASYNCLISTADDR = qhmem;
 
    dword qtdmem = qhmem + 128;
    QTD* qtd = (QTD*)qtdmem;
    qtd->NextPointer = 0;
    qtd->NextPointer |= 1;
    qtd->AlternatePointer = 0;
    qtd->AlternatePointer |= 1;
 
    qtd->Results = 0;
    qtd->Results |= 512;
    qtd->Results |= 0x80000;
    
    qtd->Buffers[0] = 0;
    dword setupbuffer = 0;
    VirtualMemory::AllocateRandomPage(true, &setupbuffer);
    qtd->Buffers[0] |= setupbuffer;
 
    byte* sb = (byte*)setupbuffer;
    sb[0] = 128;
    sb[1] = 6;
    sb[2] = 0;
    sb[3] = 1;
    sb[4] = 0;
    sb[5] = 0;
    sb[6] = 18;
    dword nextqtd = 0;
    nextqtd |= qtdmem;
    qh->Overlay[0] = nextqtd;
 
    op->USBCMD |= 32;
    while (((op->USBSTS >> 15) & 1) == 1)
    {
    }
    Video::Print("Running AsncyList\n");
    PIT::WaitMilliseconds(500);
    Video::PrintNumber(qh->CurrentQtd, 10);
}
 
void EHCI()
{
    // PCI
    DisplayEHCIPCI();
    ReadBaseRegister();
    ReadPCIReleaseNumber();
 
    //EHCI
    ParseCapibilityRegisters();
    OperateRegisters();
    byte port = Ports();
    DoTransactions(port);
 
    Keyboard::WaitForKeyDown();
    LoadKernel::DeInitializeSystems();
} 
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: USB -- EHCI

Post by pcmattman »

You didn't really elaborate on "the transaction failed" (something like a Bochs log would be useful), so I'm going to shoot into the dark here...

First: is bus mastering turned on (PCI command register)?

Second:

Code: Select all

PortBase = OperationalRegisterBase + 0x44;
Where did 0x44 come from?

Third:
What's the alignment on all the pointers you're passing as addresses for the transaction memory area? Are you passing virtual or physical addresses?
Hoozim
Member
Member
Posts: 53
Joined: Fri Jul 23, 2010 8:26 am

Re: USB -- EHCI

Post by Hoozim »

By transaction failed, I ment that there was no overlay. Bus mastering was on. 0x44 is the offset to find the PORTSC registers from the operational register base. Finally, I figured out the problem, I need to use physical addresses not virtual addresses. I did redesign my little 'test driver' so it is easier to work with. The overlays are now working but I do have a question, what is the default device address that a device is assigned when reset?

Hoozim
ppppllll1234
Posts: 13
Joined: Sat Apr 09, 2011 9:28 pm

Re: USB -- EHCI

Post by ppppllll1234 »

this code can working ?
Hoozim
Member
Member
Posts: 53
Joined: Fri Jul 23, 2010 8:26 am

Re: USB -- EHCI

Post by Hoozim »

This code does not work fully. It is only a test driver. It properly resets and configures the host controller and ports but fails to do transactions. I solved that problem and completely modified the test driver and I can now handle EHCI interrupts and sett the device address and obtain the device descriptor.
ppppllll1234
Posts: 13
Joined: Sat Apr 09, 2011 9:28 pm

Re: USB -- EHCI

Post by ppppllll1234 »

Hoozim wrote:This code does not work fully. It is only a test driver. It properly resets and configures the host controller and ports but fails to do transactions. I solved that problem and completely modified the test driver and I can now handle EHCI interrupts and sett the device address and obtain the device descriptor.
Can post the test driver code? I want to know how to read device descriptor through EHCI. Thanks.
Hoozim
Member
Member
Posts: 53
Joined: Fri Jul 23, 2010 8:26 am

Re: USB -- EHCI

Post by Hoozim »

Yes I will post the code. I can't right now but I will within the next 2 days.
Hoozim
Member
Member
Posts: 53
Joined: Fri Jul 23, 2010 8:26 am

Re: USB -- EHCI

Post by Hoozim »

Here is the code.

Here is USB.h:

Code: Select all

#ifndef USB_h
#define USB_h

#include "StandardTypedef.h"
#include "VirtualMemoryPrivate.h"

struct QTDToken
{
	byte status;
	byte pid: 2;
	byte errorCounter: 2;
	byte currPage: 3;
	byte interrupt: 1;
	word bytes: 15;
	word dataToggle: 1;
};

struct QTD
{
	dword next;
	dword nextAlt;
	struct QTDToken token;
	dword buffer0;
	dword buffer1;
	dword buffer2;
	dword buffer3;
	dword buffer4;
};

struct QHD
{
	dword HorizontalPointer;

	dword deviceAddress: 7;
	dword inactive: 1;
	dword endpoint: 4;
	dword endpointSpeed: 2;
	dword dataToggleControl: 1;
	dword H: 1;
	dword maxPacketLength: 11;
	dword controlEndpointFlag: 1;
	dword nakCountReload: 4;

	byte interruptScheduleMask;
	byte splitCompletionMask;
	word hubaddr: 7;
	word portNumber: 7;
	word mult: 2;
	dword current;
	struct QTD qtd;
};

struct EHCIRequest
{
	byte type;
	byte request;
	byte valueLo;
	byte valueHi;
	word index;
	word length;
};

void CreateQH(void* address, dword horizontalPointer, void* firstQTDPhys, byte H, dword device, dword endpoint, dword packetSize)
{
	QHD* head = (QHD*)address;
	memset(address, 0, sizeof(QHD));

	head->HorizontalPointer = horizontalPointer | 2;

	head->deviceAddress = device;
	head->inactive = 0;
	head->endpoint = endpoint;
	head->endpointSpeed = 2;
	head->dataToggleControl = 1;
	head->H = H;
	head->maxPacketLength = packetSize;
	head->controlEndpointFlag = 0;
	head->nakCountReload = 15;

	head->interruptScheduleMask = 0;
	head->splitCompletionMask = 0;
	head->hubaddr = 0;
	head->portNumber = 0;
	head->mult = 1;
	if (firstQTDPhys == 0)
		head->qtd.next = 0x1;
	else
	{
		dword physNext = VirtualMemory::PhysicalAddress((dword)firstQTDPhys);;
		head->qtd.next = physNext;
	}
}

QTD* AllocQTD(dword next)
{
	QTD* td = 0;
	VirtualMemory::AllocateRandomPage(true, (dword*)&td);
	memset(td, 0, sizeof(QTD));
	if (next != 0x1)
		td->next = VirtualMemory::PhysicalAddress(next);
	else
		td->next = 1;
	return td;
}

dword AllocQTDBuffer(QTD* td)
{
	void* data = 0;
	VirtualMemory::AllocateRandomPage(true, (dword*)&data);
	memset(data, 0, 4096);
	td->buffer0 = VirtualMemory::PhysicalAddress((dword)data);
	td->buffer1 = td->buffer2 = td->buffer3 = td->buffer4 = 0;
	return (dword)data;
}

void* CreateQTD_SETUP(dword next, bool toggle, dword tokenBytes, dword type, dword req, dword hiVal, dword loVal, dword index, dword length)
{
	QTD* td = AllocQTD(next);
	td->nextAlt = 0x1;
	td->token.status = 0x80;
	td->token.pid = 2;
	td->token.errorCounter = 3;
	td->token.currPage = 0;
	td->token.interrupt = 1;
	td->token.bytes = tokenBytes;
	td->token.dataToggle = toggle;

	dword Buffer = AllocQTDBuffer(td);
	EHCIRequest* request = (EHCIRequest*)Buffer;
	request->type = type;
	request->request = req;
	request->valueHi = hiVal;
	request->valueLo = loVal;
	request->index = index;
	request->length = length;
	return (void*)td;
}

void* CreateQTD_IO(dword next, byte direction, bool toggle, dword tokenBytes, dword* buff)
{
	QTD* td = AllocQTD(next);

	td->nextAlt = 0x1;
	td->token.status = 0x80;
	td->token.pid = direction;
	td->token.errorCounter = 3;
	td->token.currPage = 0;
	td->token.interrupt = 1;
	td->token.bytes = tokenBytes;
	td->token.dataToggle = toggle;

	dword Buffer = AllocQTDBuffer(td);
	*buff = Buffer;
	return (void*)td;	
}

#endif USB_h
and Here is the main code:

Code: Select all

#include "LoadKernel.h"
#include "Bootinfo.h"

#define GetPhysicalAddress(x) (*x & ~0xFFF)
void EHCI();


void Main(Bootinfo::MultibootInfo* bootinfo, dword kernelsize)
{
	LoadKernel::InitializeSystems(bootinfo, kernelsize);


	EHCI();
	Shell::RunShell();
	
	LoadKernel::DeInitializeSystems();
}

void Beep(byte on)
{
	OutPort(0x61, on * 163);
}


// /USB Testing -
// /-------------
// /-------------
// /-------------

#include "USB.h"

dword BaseRegister = 0;
dword OperationalRegisterBase = 0;
byte NumberOfPorts = 0;
dword PortBase = 0;

bool USBINTflag = false;

struct CapibilityRegisters
{
	byte CAPLENGTH;
	byte RESERVED;
	word HCIVERSION;
	dword HCSPARAMS;
	dword HCCPARAMS;
	byte HCSPPORTROUTE[8];
};

struct OperationRegisters
{
	dword USBCMD;
	dword USBSTS;
	dword USBINTR;
	dword FRINDEX;
	dword CTRLDSSEGMENT;
	dword PERIODICLISTBASE;
	dword ASYNCLISTADDR;
	byte Reserved[36];
	dword CONFIGFLAG;
};
OperationRegisters* op;
dword eecp = 0;

void EHCIHandler()
{
	_asm add esp, 12;
	_asm pushad;
	Video::Print("\nInterrupt Recieved");
	if (op->USBSTS & 1)
	{
		USBINTflag = true;
		Video::Print("\nUSB Interrupt\n");
		op->USBSTS |= 1;
	}
	if (op->USBSTS & 2)
	{
		Video::Print("\nUSB Error Interrupt\n");
		op->USBSTS |= 2;
	}
	if (op->USBSTS & 4)
	{
		Video::Print("\nPort Change Interrupt\n");
		op->USBSTS |= 4;
	}
	if (op->USBSTS & 0x10)
	{
		Video::Print("\nHost System Error Interrupt\n");
		op->USBSTS |= 0x10;
		Video::Print("Halting System...");
		for (;;);
	}
	if (op->USBSTS & 0x20)
	{
		Video::Print("\nInterrupt On Async Advance\n");
		op->USBSTS |= 0x20;
	}
	OutPort(0xA0, 0x20);
	OutPort(0x20, 0x20);
	_asm popad;
	_asm iretd;
}


dword ReadPci(byte bus, byte device, byte funct, byte offset)
{
	dword address = (bus << 16) | (device << 11) | (funct << 8) | (offset & 0xFC) | (0x80000000);
	OutPortDWord(0xCF8, address);
	return InPortDWord(0xCFC);
}
dword ReadPciBytes(byte bus, byte device, byte funct, byte offset)
{
	byte length = offset >> 8;
	byte regoff = offset & 0xFF;
	byte reg = regoff & 0xFC;
	byte offset2 = regoff % 0x4;

	OutPortDWord(0xCF8, 0x80000000 | (bus << 16) | (device << 11) | (funct << 8) | reg);
	dword readVal = InPortDWord(0xCFC) >> (8 * offset2);

	switch (length)
    {
        case 1:
            readVal &= 0x000000FF;
            break;
        case 2:
            readVal &= 0x0000FFFF;
            break;
        case 4:
            readVal &= 0xFFFFFFFF;
            break;
    }
    return readVal;
}
void WritePci(byte bus, byte device, byte funct, byte offset, byte data)
{
	OutPortDWord(0xCF8, (bus << 16) | (device << 11) | (funct << 8) | (offset & 0xFC) | (0x80000000));
	OutPortDWord(0xCFC, data);
}
void WritePciBytes(byte bus, byte device, byte func, byte reg, byte val)
{
	OutPortDWord(0xCF8,
        0x80000000
        | (bus     << 16)
        | (device  << 11)
        | (func    <<  8)
        | (reg & 0xFC));

	OutPort(0xCFC + (reg & 0x3), val);
}

void ShowUSBSTS()
{
	if (op->USBSTS & 1) { Video::Print("\n\nUSB Interrupt");}
	if (op->USBSTS & 2) { Video::Print("\nUSB Error Interrupt");}
	if (op->USBSTS & 4) { Video::Print("\nPort Change Detect");}
	if (op->USBSTS & 8) { Video::Print("\nFrame List Rollover");}
	if (op->USBSTS & 0x10) { Video::Print("\nHost System Error");}
	if (op->USBSTS & 0x20) { Video::Print("\nInterrupt on Async Advance");}
	if (op->USBSTS & 0x1000) { Video::Print("\nHCHalted");}
	if (op->USBSTS & 0x2000) { Video::Print("\nReclamation");}
	if (op->USBSTS & 0x4000) { Video::Print("\nPeriodic Schedule Status");}
	if (op->USBSTS & 0x8000) { Video::Print("\nAsynchronous Schedule Status\n\n");}
}

void DisplayEHCIPCI()
{
	dword classcode = ReadPci(0, 3, 3, 8);
	Video::Print("Class code: ");
	Video::PrintNumber((classcode >> 24) & 0xFF, 16);
	Video::Print(" Sub class code: ");
	Video::PrintNumber((classcode >> 16) & 0xFF, 16);
	Video::Print(" Programming Interface: ");
	Video::PrintNumber((classcode >> 8) & 0xFF, 16);

	dword commandRegister = ReadPci(0, 3, 3, 4);
	Video::Print(" Command Register: ");
	Video::PrintNumber(commandRegister, 10);

	dword irqline = ReadPci(0, 3, 3, 0x3C);
	irqline &= 0xFF;
	Video::Print(" IRQ: ");
	Video::PrintNumber(irqline, 10);
	IDT::InstallIRQ((dword)&EHCIHandler, 0x8, PModeGate | PresentGate, 41);

	Video::Print("\n\n");
}

void ReadBaseRegister()
{
	dword base = ReadPci(0, 3, 3, 0x10);
	Video::Print("Base register address: 0x");
	Video::PrintNumber(base, 16);
	Video::Print("  -  ");
	Video::PrintNumber(base, 10);
	VirtualMemory::AllocateRandomPage(true, &BaseRegister);
	VirtualMemory::FreePage(BaseRegister);
	VirtualMemory::MapPage((void*)base, (void*)BaseRegister);
	Video::Print("\n\n");
}

void ReadPCIReleaseNumber()
{
	dword num = ReadPci(0, 3, 3, 0x60);
	Video::Print("Serial Bus Release Number: ");
	Video::PrintNumber((byte)num, 16);
	Video::Print("\n\n");
}

void CapibilityPortsHCS(dword HCSPARAMS)
{
	byte NOPs = (HCSPARAMS & 0xF);
	Video::Print("\nNOPs: ");
	Video::PrintNumber(NOPs, 10);
	NumberOfPorts = NOPs;

	byte DebugPortNumber = (HCSPARAMS & 0xFF000000);
	Video::Print("    Debug Port: ");
	Video::PrintNumber(DebugPortNumber, 10);

	byte PortPower = ((HCSPARAMS >> 4) & 1);
	Video::Print("    Port Power: ");
	Video::PrintNumber(PortPower, 10);
}

void ParseCapibilityRegisters()
{
	CapibilityRegisters cap = *((CapibilityRegisters*)BaseRegister);
	Video::Print("CAPLENGTH: ");
	Video::PrintNumber(cap.CAPLENGTH, 10);
	OperationalRegisterBase = (BaseRegister + cap.CAPLENGTH);

	Video::Print("\nHCIVERSION: ");
	Video::PrintNumber(cap.HCIVERSION, 16);

	CapibilityPortsHCS(cap.HCSPARAMS);
	eecp = (((cap.HCCPARAMS) >> 8) & 0xFF);
	Video::Print("\n\n");
}

void OperateRegisters()
{
	op = ((OperationRegisters*)OperationalRegisterBase);
	op->USBCMD &= ~1;
	while (!(op->USBSTS & 0x1000))
	{
		PIT::WaitMilliseconds(30);
	}
	op->USBCMD |= 2;
	while ((op->USBCMD & 2) != 0)
	{
		PIT::WaitMilliseconds(20);
	}

	Video::Print("Host Controller Reset\n\n");

	op->CTRLDSSEGMENT = 0;
	op->USBINTR = 0x20 | 0x10 | 4 | 2 | 1;
	if (op->USBSTS & 0x1000)
	{
		op->USBCMD |= 1;
		while (op->USBSTS & 0x1000)
		{
		}
		Video::Print("Host Controller started.");
	}
	op->CONFIGFLAG = 1;
	PIT::WaitMilliseconds(100);

	PortBase = OperationalRegisterBase + 0x44;
}

dword* SelectPort(byte portnumber)
{
	return (dword*)(PortBase + (portnumber * 4));
}

byte Ports()
{
	while (true)
	{
		for (int i = 0; i < NumberOfPorts; i++)
		{
			dword* base = SelectPort(i);
			dword enable = (((*base) >> 0) & 1);
			if (enable)
			{
				Video::Print("Device has been inserted into port: ");
				Video::PrintNumber(i, 10);

				Beep(1);
				op->USBINTR = 0;
				*base |= 256;
				PIT::WaitMilliseconds(100);
				*base &= ~256;
				PIT::WaitMilliseconds(50);
				op->USBINTR = 0x20 | 0x10 | 4 | 2 | 1;
				Beep(0);

				Video::Print(" With data code: ");
				Video::PrintNumber(*base, 10);
				Video::NewLine();

				return i;
			}
		}
	}
}

void DoAsync()
{
	op->USBSTS |= 1;
	USBINTflag = false;

	op->USBCMD |= (0x20);
	while (!(op->USBSTS & 0x8000))
	{
		PIT::WaitMilliseconds(20);
	}
	op->USBCMD |= 0x40;
	PIT::WaitMilliseconds(100);
	while (!USBINTflag)
	{
		PIT::WaitMilliseconds(20);
	}
	op->USBSTS |= 1;
	USBINTflag = false;

	op->USBCMD &= ~0x20;
	Video::Print("\nTransaction Completed\n");
}

struct DeviceDesc
{
	byte Length;
	byte DescType;
	word bcdUSB;
	byte DeviceClass;
	byte SubClass;
	byte Protocal;
	byte MaxPacketSize;
	word Vendor;
	word Product;
	word bcdDevice;
	byte Manufacturer;
	byte ProductIndex;
	byte Serial;
	byte NumConfigs;
};

void NextTransAction()
{
	void* virtAList = 0;
	VirtualMemory::AllocateRandomPage(true, (dword*)&virtAList);
	op->USBCMD &= ~0x20;
	op->ASYNCLISTADDR = VirtualMemory::PhysicalAddress((dword)virtAList);

	dword buff = 0;
	void* next = CreateQTD_IO(1, 0, 1, 0, &buff);
	next = CreateQTD_IO((dword)next, 1, 1, 18, &buff);
	void* setup = CreateQTD_SETUP((dword)next, 0, 8, 0x80, 6, 1, 0, 0, 18);

	CreateQH(virtAList, VirtualMemory::PhysicalAddress((dword)virtAList), setup, 1, 5, 0, 64);
	DoAsync();

	DeviceDesc* dev = (DeviceDesc*)((dword*)buff);
	Video::Print("\n\n\nDevice Descriptor\n\n");
	Video::PrintNumber(dev->Length, 10);
	Video::NewLine();
	Video::PrintNumber(dev->DescType, 10);
	Video::NewLine();
	Video::PrintNumber(dev->bcdUSB, 10);
	Video::NewLine();
	Video::PrintNumber(dev->DeviceClass, 10);
	Video::NewLine();
	Video::PrintNumber(dev->SubClass, 10);
	Video::NewLine();
	Video::PrintNumber(dev->Protocal, 10);
	Video::NewLine();
	Video::PrintNumber(dev->MaxPacketSize, 10);
	Video::NewLine();
	Video::PrintNumber(dev->Vendor, 10);
	Video::NewLine();
	Video::PrintNumber(dev->Product, 10);
	Video::NewLine();
	Video::PrintNumber(dev->bcdDevice, 10);
	Video::NewLine();
	Video::PrintNumber(dev->Manufacturer, 10);
	Video::NewLine();
	Video::PrintNumber(dev->ProductIndex, 10);
	Video::NewLine();
	Video::PrintNumber(dev->Serial, 10);
	Video::NewLine();
	Video::PrintNumber(dev->NumConfigs, 10);
	for (;;);
}

void DoTransactions(byte port)
{
	Video::Print("Press any key to continue...\n");
	Keyboard::WaitForKeyDown();

	void* virtAList = 0;
	VirtualMemory::AllocateRandomPage(true, (dword*)&virtAList);
	op->USBCMD &= ~0x20;
	op->ASYNCLISTADDR = VirtualMemory::PhysicalAddress((dword)virtAList);

	dword buff = 0;
	void* next = CreateQTD_IO(1, 1, 1, 0, &buff);
	void* setupQtd = CreateQTD_SETUP((dword)next, 0, 8, 0, 5, 0, 5, 0, 0);

	CreateQH(virtAList, VirtualMemory::PhysicalAddress((dword)virtAList), setupQtd, 1, 0, 0, 64);

	DoAsync();

	NextTransAction();

	
}

void EHCI()
{
	// PCI
	DisplayEHCIPCI();
	ReadBaseRegister();
	ReadPCIReleaseNumber();

	//EHCI
	ParseCapibilityRegisters();
	OperateRegisters();
	byte port = Ports();
	DoTransactions(port);

	Video::Print("\n\n\nPress any key to shut down...\n\n");
	Keyboard::WaitForKeyDown();
	LoadKernel::DeInitializeSystems();
}
The code enters in at Main().
Remember this is just a test driver so it is horribly unorganised and has magic numbers everywhere so if you have any questions, I can answer them for you.
Post Reply