Page 1 of 1

UHCI root hub port reset (quirk?)

Posted: Wed Mar 16, 2011 3:27 pm
by orome
Hi,
I've seen problems similar to mine here and elsewhere but was unable to find a definite answer.
I'm part of a team bringing USB support to an academic OS, and so far everything was good.
We got several devices working and tested on real hw (mouse, keyboard, hubs), however some are causing problems (namely Microsoft IntelliMouse Optical).
After plugging in the mouse it responds to the first SETUP packet with Timeout/CRC and ultimately Stall, exact value of of TD status field is 4450007 (LOW SPEED, STALL, CRC/TIMEOUT, RESERVED BIT, 8 bytes transfered, what is this thing with reserved status bit(bit 16) set?)

Funny thing is that it works with other devices that i tried, Logitech keyboard, Genius mouse, usb hubs. The fact that the same microsoft mouse works when connected via another hub, has led me to believe that problem is with UHCI port reset routine (it's the only thing that differs).
my reset routine, called immediately after CSC bit is detected and bit 0 indicates there is a device connected:

Code: Select all

mwait(100) /* 100ms, my understanding is that this one is not necessary and 100ms timeout shall be provided by UHCI before indicating the device presence, but can't hurt */

port_write(0x0200) /* starts reset signaling */
mwait(50) /* 50 ms, USB spec 7.1.7.3 mentions that reset from root hub ports should be 50 ms, however OHCI does not do it, and sends reset signal for 10ms  (UHCI 1.0a p. 131) */
port_write(0) /* stops reset signaling, keeps CSC, and possibly PCE bits untouched */

p = port_read()
p |= 0x4
port_write(p); /* this sets port to enabled state, and clears WC bits */

mwait(10)   /* 10 ms reset recovery */
the first SETUP packet requests 8 bytes of device descriptor. (and succeeds if this mouse is connected via external hub)

during my experiments I found out that devices react differently to incorrect/absent reset, some worked even without a reset signal, some responded NAK to everything, and some responded the same way as this MS mouse (another thing that let me believe there is something wrong with reset sequence)

is there something I missed, or some kind of quirk that certain devices need?
any input is welcome as I am stuck on this.
thanks

PS: The mouse works well with both Linux and Windows,
out of 3(different models) Microsoft optical mice I tried, only one worked, other devices I tried don't have this problem

Re: UHCI root hub port reset (quirk?)

Posted: Thu Mar 17, 2011 9:33 am
by Brynet-Inc
Several OS's deviate from that 50ms standards requirement, as a workaround for buggy devices, try 100 or 150.

Microsoft USB devices are always flaky btw, this isn't news.

Re: UHCI root hub port reset (quirk?)

Posted: Fri Mar 18, 2011 6:46 pm
by orome
Thanks for your reply, I tried several timing settings, from 10ms to 1s and it did not help.

I dug into several uhci drivers and checked the timings used there:
OS | reset duration | post reset wait
DOS: 55ms 55ms (comments say > 50ms)
Apple: 10ms 100ms
HAIKU: 250ms 1ms (then waits 50ms to confirm port enabled)
Linux(2.6.38): 50ms 10us

I tried all of the combinations and none worked.
Funny thing is that once it somehow worked, but I have been unable to replicate this ever since.

I use linux daily and tried haiku live CD, the mouse works in both.

When the initialization sequence was repeated 100 times(100ms and 1s pauses) I got 100 errors. (that should rule out some random timing error).
I did not check connections status between iterations and after removing the mouse it continued with the same error (i.e. the mouse is dead and refuses to communicate).

All UHCI root ports are powered(no way to change it), and I do not touch suspend/resume bits.

Re: UHCI root hub port reset (quirk?) [solved]

Posted: Sun May 08, 2011 1:59 pm
by orome
OK I finally figured this one.
For those who are interested:
I got reset recovery period wrong, I used it to wait after reset before enabling the port, while it should be the time from reset to data communication with the device. On the other hand USB specification mentions(7.1.7.4) that device that must be in suspended state after 10ms.
Thus, these devices (Microsoft mice and a Kingston flash disk) were in suspend state by the time the host tried to communicate. I don't know why those devices failed to resume when the idle signalling ceased (as specified in 7.1.7.5).

The solution was to wait the right amount of time between the end of reset signalling and port enabling. If it is done immediately, the port fails to enable, too much time, and devices enter suspend state.

Hope this helps somebody.

PS: I should mention that this: http://www.seabios.org/pipermail/seabio ... 00321.html
Don't leave USB UHCI ports disabled for extended time during reset.

Disabling the port will cause device to go into suspend - so don't do
that during the reset sequence

pointed me in the right direction

Re: UHCI root hub port reset (quirk?)

Posted: Mon Aug 29, 2011 3:30 pm
by andymc
This was very helpful, thank you. I was experiencing the exact same symptoms with a few of my USB peripherals.

So, what worked for me was:

1. Set reset bit
2. Wait 50ms
3. Clear reset bit
4. Set enabled bit
5. Wait 10ms
6. Proceed with enumeration

Cheers! =D>
Andy

Re: UHCI root hub port reset (quirk?)

Posted: Thu Dec 31, 2015 2:13 pm
by alwaysnub
I don't want to bump an old thread, but for anyone who's interested.

@ orome
The solution was to wait the right amount of time between the end of reset signalling and port enabling. If it is done immediately, the port fails to enable, too much time, and devices enter suspend state.
I have found that waiting for a connect status change works best.
Disabling the port will cause device to go into suspend - so don't do
that during the reset sequence
The UHCI specification states that "When in the Reset State, the port is disabled and sends the USB Reset signaling", so that should not be a problem.

@ andymc
1. Set reset bit
2. Wait 50ms
3. Clear reset bit
4. Set enabled bit
5. Wait 10ms
6. Proceed with enumeration
Most of my flash drives was timing out because of step 5 (Wait 10ms). I increased it to 24ms and they stopped timing out.

@ All

So what works for me is:

1. Set reset bit.
2. Wait 58ms.
3. Clear reset bit.
4. Wait for connect status change.
5. Set enable bit.
6. Wait for enable bit to actually change.
7. Wait 24ms.
8. Proceed with enumeration.

Some Code:

Code: Select all

/* Turning reset off causes a port connect status change. */
ERROR API uhci_WaitForCSC(PUHCI HC, BYTE Port)
{
	WORD I, Status;

	for (I = 0; I < 100; I++) // Timeout at 400ms (4ms * 100).
	{
		Sleep(4);
		Status = InW(HC->BAR + UHCI_PORTSC1 + (2*Port));
		if (Status & UHCI_PORT_CS_CHANGE) return ERROR_NONE;
	}

	return ERROR_USB_TIMEOUT;
}

/* UHCI_PORT_ENABLE Bit does not change until the port state actually changes. */
ERROR API uhci_WaitForEnabledPort(PUHCI HC, BYTE Port)
{
	WORD I, Status;

	for (I = 0; I < 100; I++) // Timeout at 200ms (2ms * 100).
	{
		Sleep(2);
		Status = InW(HC->BAR + UHCI_PORTSC1 + (2*Port));
		if (Status & UHCI_PORT_ENABLE) return ERROR_NONE;
	}

	return ERROR_USB_TIMEOUT;
}

VOID API uhci_ResetPort(PUHCI HC, BYTE Port)
{
	// Reset.
	OutW(HC->BAR + UHCI_PORTSC1 + (2*Port), UHCI_PORT_RESET);

	// Wait.
	Sleep(58);

	// Clear Reset Bit.
	OutW(HC->BAR + UHCI_PORTSC1 + (2*Port), InW(HC->BAR + UHCI_PORTSC1 + (2*Port)) & ~UHCI_PORT_RESET);

	// Wait for a connect status change. HP's server management chip requires a longer delay.
	uhci_WaitForCSC(HC, Port);

	// Enable, and Clear Change-Bits (Connected & Enabled).
	OutW(HC->BAR + UHCI_PORTSC1 + (2*Port), UHCI_PORT_CS_CHANGE|UHCI_PORT_ENABLE|UHCI_PORT_ENABLE_CHANGE);

	// Wait for the port to become enabled.
	uhci_WaitForEnabledPort(HC, Port);

	//Wait.
	Sleep(24);
}