Re: EHCI didn't works at real PC and VirtualBox!
Posted: Thu Aug 02, 2018 4:13 pm
Ben, may i send all code to you to help me? If yes, please reply to email: [email protected].
With best regards,
Aleksandr
With best regards,
Aleksandr
The Place to Start for Operating System Developers
https://forum.osdev.org/
Yes. I have sent you an email at that address. For future reference, it is wise to not display your full address. For example, next time use ivningman [at] gmail [dot] comMrLolthe1st wrote:Ben, may i send all code to you to help me? If yes, please reply to email: ivningman [at] gmail [dot] com.
With best regards,
Aleksandr
Code: Select all
1) You are not resetting the controller to begin with.
The controller is probably in the Run State due to the BIOS
You are writing to registers that should not be written to while in the run state.
2) You are setting the Interrupt Threshold to 16-micro frames, should be 8-micro frames.
3) When you write a reset bit to the EHCI port register, you don't write a zero to the Port Enable bit.
(See the description for Bit 8 in the ECHI specs (Table 2-16))
You should also clear the Connect Status Change bit before you try to do a reset
4) The last read you do from the connected port is 0x00001005
CCS = 1
PED = 1
PP = 1
Then nothing happens. Most likely you are now placing TD's on the stack.
Code: Select all
VBoxDbg> info ehci
USBCMD: 80031
EHCI_CMD_RUN
EHCI_CMD_PERIODIC_SCHED_ENABLE
EHCI_CMD_ASYNC_SCHED_ENABLE
Code: Select all
USBINTR: 0
FRINDEX: 4a5800
CTRLDSSEGMENT: 0
Code: Select all
1024 * 8 (0x400 * 0x008) = 8192 - 1 (0x2000 - 1)Code: Select all
(1023 * 8) + 7 = 8192 - 1Code: Select all
uint cmd = ROR(usbCmdO);
WOR(usbCmdO, 2 | cmd & ~(CMD_ASE | CMD_PSE));
kprintf("!%x!", ROR(usbCmdO));
while (ROR(usbCmdO) & 2);
while ((ROR(usbCmdO) & STS_HCHALTED));
cmd = ROR(usbCmdO);
WOR(usbCmdO, 2 | cmd & ~(1));
Code: Select all
uint cmd = ROR(usbCmdO);
WOR(usbCmdO, 2 | cmd & ~(CMD_ASE | CMD_PSE));
kprintf("!%x!", ROR(usbCmdO));
while (ROR(usbCmdO) & 2);
while ((ROR(usbCmdO) & STS_HCHALTED));
Code: Select all
cmd = ROR(usbCmdO);
WOR(usbCmdO, 2 | cmd & ~(1));
Code: Select all
// Read the Command register
uint cmd = ROR(usbCmdO);
// Write it back, setting bit 2 (the Reset bit)
// and making sure the two schedule Enable bits are clear.
WOR(usbCmdO, 2 | cmd & ~(CMD_ASE | CMD_PSE));
// A small delay here would be good. You don't want to read
// the register before it has a chance to actually set the bit
ROR(usbCmndO);
// Now wait for the controller to clear the reset bit.
// Note: A timeout would be a good idea too in case the bit
// never becomes clear. (Bad controller: Bad address: etc.) (See note 1 below)
while (ROR(usbCmdO) & 2);
// Again, a small delay here would be good to allow the
// reset to actually become complete.
ROR(usbCmndO);
// wait for the halted bit to become set
// again, see note 1 below)
while (!(ROR(usbStatO) & STS_HCHALTED));
Code: Select all
while (ROR(usbCmdO) & 2);
Code: Select all
// ------------------------------------------------------------------------------------------------
// Port Status
#define PORT_CONNECTION (1 << 0) // Current Connect Status
#define PORT_ENABLE (1 << 1) // Port Enabled
#define PORT_SUSPEND (1 << 2) // Suspend
#define PORT_OVER_CURRENT (1 << 3) // Over-current
#define PORT_RESET (1 << 4) // Port Reset
#define PORT_POWER (1 << 8) // Port Power
#define PORT_SPEED_MASK (3 << 9) // Port Speed
#define PORT_SPEED_SHIFT 9
#define PORT_TEST (1 << 11) // Port Test Control
#define PORT_INDICATOR (1 << 12) // Port Indicator Control
#define PORT_CONNECTION_CHANGE (1 << 16) // Connect Status Change
#define PORT_ENABLE_CHANGE (1 << 17) // Port Enable Change
#define PORT_OVER_CURRENT_CHANGE (1 << 19) // Over-current Change
// ------------------------------------------------------------------------------------------------
typedef struct UsbHub
{
UsbDevice *dev;
UsbHubDesc desc;
} UsbHub;
// ------------------------------------------------------------------------------------------------
static uint UsbHubResetPort(UsbHub *hub, uint port)
{
UsbDevice *dev = hub->dev;
// Reset the port
if (!UsbDevRequest(dev,
RT_HOST_TO_DEV | RT_CLASS | RT_OTHER,
REQ_SET_FEATURE, F_PORT_RESET, port + 1,
0, 0))
{
return 0;
}
PitWait(1000);
// Wait 100ms for port to enable (TODO - remove after dynamic port detection)
u32 status = 0;
for (uint i = 0; i < 10; ++i)
{
// Delay
PitWait(1000);
// Get current status
if (!UsbDevRequest(dev,
RT_DEV_TO_HOST | RT_CLASS | RT_OTHER,
REQ_GET_STATUS, 0, port + 1,
sizeof(status), &status))
{
return 0;
}
kprintf("!%x!",status);
// Check if device is attached to port
if (~status & PORT_CONNECTION)
{
break;
}
/*
// Acknowledge change in status
if (status & (PORT_ENABLE_CHANGE | PORT_CONNECTION_CHANGE))
{
port_clr(reg, PORT_ENABLE_CHANGE | PORT_CONNECTION_CHANGE);
continue;
}*/
// Check if device is enabled
if (status & PORT_ENABLE)
{
break;
}
}
return status;
}
// ------------------------------------------------------------------------------------------------
static void UsbHubProbe(UsbHub *hub)
{
UsbDevice *dev = hub->dev;
uint portCount = hub->desc.portCount;
// Enable power if needed
if ((hub->desc.chars & HUB_POWER_MASK) == HUB_POWER_INDIVIDUAL)
{
printTextToWindow(1, mywin, "Switching on the power!!\n");
for (uint port = 0; port < portCount; ++port)
{
if (!UsbDevRequest(dev,
RT_HOST_TO_DEV | RT_CLASS | RT_OTHER,
REQ_SET_FEATURE, F_PORT_POWER, port + 1,
0, 0))
{
return;
}
}
PitWait(hub->desc.portPowerTime * 10);
}
printTextToWindow(2, mywin, " Hub port count: %x\n",(int)portCount);
// Reset ports
for (uint port = 0; port < portCount; ++port)
{
uint status = UsbHubResetPort(hub, port);
if (status & PORT_ENABLE)
{
uint speed = (status & PORT_SPEED_MASK) >> PORT_SPEED_SHIFT;
printTextToWindow(2, mywin, " Port #%x enabled!\n", port);
UsbDevice *dev = UsbDevCreate();
if (dev)
{
dev->parent = hub->dev;
dev->hc = hub->dev->hc;
dev->port = port;
dev->speed = speed;
dev->maxPacketSize = 8;
dev->hcControl = hub->dev->hcControl;
dev->hcIntr = hub->dev->hcIntr;
if (!UsbDevInit(dev))
{
// TODO - cleanup
}
}
}
}
}
// ------------------------------------------------------------------------------------------------
static void UsbHubPoll(UsbDevice *dev)
{
}
// ------------------------------------------------------------------------------------------------
void _usbhubinit(UsbDevice *dev)
{
if (dev->intfDesc->intfClass == USB_CLASS_HUB)
{
printTextToWindow(2, mywin, " Initializing Hub\n");
// Get Hub Descriptor
UsbHubDesc desc;
if (!UsbDevRequest(dev,
RT_DEV_TO_HOST | RT_CLASS | RT_DEV,
REQ_GET_DESC, (USB_DESC_HUB << 8) | 0, 0,
sizeof(UsbHubDesc), &desc))
{
return 0;
}
UsbPrintHubDesc(&desc);
UsbHub *hub = malloc(sizeof(UsbHub));
hub->dev = dev;
hub->desc = desc;
dev->drv = hub;
dev->drvPoll = UsbHubPoll;
UsbHubProbe(hub);
return 1;
}
return 0;
}Glad to hear that real hardware is now working. The Reset was the key, most likely.MrLolthe1st wrote:So, OK. EHCI successfully works at real hardware! But, don't working at VBox. Next trouble is:
My OS detects HUB with 8 ports, with characteristics 0x0 and power time 0, current = 0. But, i'm trying to reset any port i'm recieving status 0.
Code below.
What it may be?
With best regards,
Aleksandr
I understand that there is a language difference and English may not be your primary language. So let me try to explain this a little better and then please let me know which type of Hub you are trying to reset.MrLolthe1st wrote:Hub, that connected to EHCI port, likely root hub, but i'm don't know.
Okay, then this assumes that you have now have Queues and Transfer Descriptors working properly. Yes?MrLolthe1st wrote:Hub, which is connected to one of ports EHCI.