usb uhci IO-TD stalled

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
alwaysnub
Posts: 20
Joined: Sat Aug 14, 2010 9:49 pm

usb uhci IO-TD stalled

Post by alwaysnub »

Hi all.

Iv been trying to get the Device-Descriptor for Hi-Speed usb devices using the uhci.
The Setup TD always executes fine, but the following IO-TD always fires a usb error interrupt and reports a stalled error.
I have tried numerous things to fix it, such as changing the D-Toggle bits, changing my port reset procedure and calling SetDeviceAddress before GetDeviceDescriptor.
I don't think my port reset procedure is a problem sense the Setup TD executes fine.

My usb test device is a Logitech keyboard.
I'm lost at what the problem could be.

My uhci_ControlIn always reports a stalled error on the Data-TD, and on the handshake-TD for uhci_ControlSet

Let me know if you see anything wrong with this code:

Code: Select all

PUHCI_TRANSFER_DESCRIPTOR AllocateTD(PUHCI_TRANSFER_DESCRIPTOR Next, USB_SPEED Speed)
{
	PUHCI_TRANSFER_DESCRIPTOR TD;

	TD = (PUHCI_TRANSFER_DESCRIPTOR) Malloc(sizeof(UHCI_TRANSFER_DESCRIPTOR));
	if (TD != 0)
	{
		MemSet(TD, 0, sizeof(UHCI_TRANSFER_DESCRIPTOR));
		if ((SIZE_PTR)Next != BIT_T) TD->Next = ((SIZE_PTR)Next & 0xFFFFFFF0) | BIT_Vf;
		else TD->Next = BIT_T;
		TD->ErrorCounter = 3; // Stop after 3 errors.
		TD->Active = 1; // Execute This Transaction.
		if (Speed == USB_LOWSPEED) TD->LowSpeedDevice = TRUE;
	}

	return TD;
}

PUHCI_TRANSFER_DESCRIPTOR uhci_CreateTD_Setup(PUHCI_TRANSFER_DESCRIPTOR Next, PUSB_REQUEST Request, USB_SPEED Speed, BYTE Toggle, DWORD Device, BYTE Endpoint)
{
	PUHCI_TRANSFER_DESCRIPTOR TD;

	TD = AllocateTD(Next, Speed);
	if (TD != 0)
	{
		TD->PacketId = UHCI_TD_SETUP; // SETUP
		TD->MaxLength = 8 - 1; // Setup length is always 8
		TD->DataToggle = Toggle; // Should be toggled every list entry.
		TD->DeviceAddress = Device; // The device address.
		TD->Endpoint = Endpoint; // Endpoint number on the device serving as the data source or sink.
		TD->Buffer = (DWORD) Request; // USB Request info.
	}

	return TD;
}

PUHCI_TRANSFER_DESCRIPTOR uhci_CreateTD_IO(PUHCI_TRANSFER_DESCRIPTOR Next, USB_SPEED Speed, BYTE Direction, BYTE Toggle, WORD TokenBytes, DWORD Device, BYTE Endpoint, PVOID Buffer)
{
	PUHCI_TRANSFER_DESCRIPTOR TD;

	TD = AllocateTD(Next, Speed);
	if (TD != 0)
	{
		TD->PacketId = Direction; // UHCI_TD_IN or UHCI_TD_OUT
		if (TokenBytes) TD->MaxLength = (TokenBytes - 1) & 0x7FF;
		else TD->MaxLength = 0x7FF; // Null data packet.
		TD->DataToggle = Toggle; // Should be toggled every list entry.
		TD->DeviceAddress = Device; // The device address.
		TD->Endpoint = Endpoint; // Endpoint number on the device serving as the data source or sink.
		TD->Buffer = (DWORD) Buffer; // Buffer to read or write.
	}

	return TD;
}

ERROR API uhci_ControlSet(PUSB_DEVICE_INFO UsbDevice, PUSB_REQUEST Request)
{
	PUHCI HC;
	PUHCI_TRANSFER_DESCRIPTOR SetupToken;
	PUHCI_TRANSFER_DESCRIPTOR HandshakeToken;
	ERROR Error;

	HC = (PUHCI) UsbDevice->Device->Controller;

	HandshakeToken = uhci_CreateTD_IO((PUHCI_TRANSFER_DESCRIPTOR)BIT_T, UsbDevice->Speed, UHCI_TD_IN, TRUE, 0, UsbDevice->Address, 0, 0);
	SetupToken = uhci_CreateTD_Setup(HandshakeToken, Request, UsbDevice->Speed, FALSE, UsbDevice->Address, 0);

	uhci_CreateQH(HC, HC->QH, SetupToken);

	// Run scheduler.
	OutW(HC->BAR + UHCI_FRNUM, 0);
	OutW(HC->BAR + UHCI_USBCMD, InW(HC->BAR + UHCI_USBCMD) | UHCI_CMD_RS);

	// Wait for completion.
	while ((SetupToken->Active == 1) || (HandshakeToken->Active == 1) && (HC->UsbIntError == FALSE));

	// Stop scheduler.
	OutW(HC->BAR + UHCI_USBCMD, InW(HC->BAR + UHCI_USBCMD) & ~UHCI_CMD_RS);

	// Wait for stop.
	while (!(InW(HC->BAR + UHCI_USBSTS) & UHCI_STS_HCHALTED));

	// Reset UHCI_STS_HCHALTED bit.
	OutW(HC->BAR + UHCI_USBSTS, UHCI_STS_HCHALTED);

	if ((HandshakeToken->BitstuffError|SetupToken->BitstuffError) != 0) Error = ERROR_USB_OTHER;
	else if ((HandshakeToken->DataBufferError|SetupToken->DataBufferError) != 0) Error = ERROR_USB_DATA_BUFFER;
	else if ((HandshakeToken->BabbleDetected|SetupToken->BabbleDetected) != 0) Error = ERROR_USB_BABBLE;
	else if ((HandshakeToken->CRC_TimeOutError|SetupToken->CRC_TimeOutError) != 0) Error = ERROR_USB_TIMEOUT;
	else if ((HandshakeToken->NakReceived|SetupToken->NakReceived) != 0) Error = ERROR_USB_TRANSACTION;
	else if ((HandshakeToken->Stalled|SetupToken->Stalled) != 0) Error = ERROR_USB_HALTED;
	else Error = ERROR_NONE;

	Free(HandshakeToken);
	Free(SetupToken);

	return Error;
}

ERROR API uhci_ControlIn(PUSB_DEVICE_INFO UsbDevice, PVOID Buffer, PUSB_REQUEST Request)
{
	PUHCI HC;
	PUHCI_TRANSFER_DESCRIPTOR SetupToken;
	PUHCI_TRANSFER_DESCRIPTOR DataToken;
	PUHCI_TRANSFER_DESCRIPTOR HandshakeToken;
	ERROR Error;

	HC = (PUHCI) UsbDevice->Device->Controller;

	HandshakeToken = uhci_CreateTD_IO((PUHCI_TRANSFER_DESCRIPTOR)BIT_T, UsbDevice->Speed, UHCI_TD_OUT, TRUE, 0, UsbDevice->Address, 0, 0);
	DataToken = uhci_CreateTD_IO(HandshakeToken, UsbDevice->Speed, UHCI_TD_IN, FALSE, Request->Length, UsbDevice->Address, 0, Buffer);
	SetupToken = uhci_CreateTD_Setup(DataToken, Request, UsbDevice->Speed, FALSE, UsbDevice->Address, 0);

	uhci_CreateQH(HC, HC->QH, SetupToken);

	// Run scheduler.
	OutW(HC->BAR + UHCI_FRNUM, 0);
	OutW(HC->BAR + UHCI_USBCMD, InW(HC->BAR + UHCI_USBCMD) | UHCI_CMD_RS);

	// Wait for completion.
	while ((SetupToken->Active == 1) || (DataToken->Active == 1) || (HandshakeToken->Active == 1) && (HC->UsbIntError == FALSE));

	// Stop scheduler.
	OutW(HC->BAR + UHCI_USBCMD, InW(HC->BAR + UHCI_USBCMD) & ~UHCI_CMD_RS);

	// Wait for stop.
	while (!(InW(HC->BAR + UHCI_USBSTS) & UHCI_STS_HCHALTED));

	// Reset UHCI_STS_HCHALTED bit.
	OutW(HC->BAR + UHCI_USBSTS, UHCI_STS_HCHALTED);

	if ((HandshakeToken->BitstuffError|DataToken->BitstuffError|SetupToken->BitstuffError) != 0) Error = ERROR_USB_OTHER;
	else if ((HandshakeToken->DataBufferError|DataToken->DataBufferError|SetupToken->DataBufferError) != 0) Error = ERROR_USB_DATA_BUFFER;
	else if ((HandshakeToken->BabbleDetected|DataToken->BabbleDetected|SetupToken->BabbleDetected) != 0) Error = ERROR_USB_BABBLE;
	else if ((HandshakeToken->CRC_TimeOutError|DataToken->CRC_TimeOutError|SetupToken->CRC_TimeOutError) != 0) Error = ERROR_USB_TIMEOUT;
	else if ((HandshakeToken->NakReceived|DataToken->NakReceived|SetupToken->NakReceived) != 0) Error = ERROR_USB_TRANSACTION;
	else if ((HandshakeToken->Stalled|DataToken->Stalled|SetupToken->Stalled) != 0) Error = ERROR_USB_HALTED;
	else Error = ERROR_NONE;

	Free(HandshakeToken);
	Free(DataToken);
	Free(SetupToken);

	return Error;
}
TomT
Member
Member
Posts: 42
Joined: Sat Mar 15, 2008 7:20 am
Location: Wisconsin, USA
Contact:

Re: usb uhci IO-TD stalled

Post by TomT »

I dont have a uhci driver for keyboard, but HID devices like mouse are low speed devices, and I thought keyboard was also low speed.

You might examine the raw hex bytes of your Transfer Descriptor and compare them to the usb 1.0 spec.

TomT

https://code.google.com/p/tatos/
alwaysnub
Posts: 20
Joined: Sat Aug 14, 2010 9:49 pm

Re: usb uhci IO-TD stalled

Post by alwaysnub »

Yes, sorry that was a typo, i meant Full-Speed device Not Hi-Speed.

I have a Logitech keyboard and mouse that show as Full-Speed in the port status/control register.
After reset of the port, it shows a 0x95 value, that appears to be correct.
alwaysnub
Posts: 20
Joined: Sat Aug 14, 2010 9:49 pm

Re: usb uhci IO-TD stalled

Post by alwaysnub »

After checking the raw dwords of the TD's, i noticed the Buffer dword was way out of range.
Turns out the way i declared my TD was creating the problem.

Instead of declaring the Token (dword 2) like this:

Code: Select all

        BYTE PacketId;
	DWORD DeviceAddress     : 7;
	DWORD Endpoint          : 4;
	DWORD DataToggle        : 1;
	DWORD Reserved3         : 1;
	DWORD MaxLength         : 11;
It should have been like this:

Code: Select all

        DWORD PacketId          : 8;
	DWORD DeviceAddress     : 7;
	DWORD Endpoint          : 4;
	DWORD DataToggle        : 1;
	DWORD Reserved3         : 1;
	DWORD MaxLength         : 11;
Now i face a new problem. When i call GetDeviceDescriptor with a length of 8, the device responds with a 0 length data packet.
But when i call with a length of 18, the device responds with a 8 length data packet and the data is not for a device descriptor but instead for an interface.
Iv check the raw bytes of the request, and all the data looks correct.

Are devices aloud to respond with an interface descriptor?
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: usb uhci IO-TD stalled

Post by SpyderTL »

No. An interface descriptor should never be returned by itself regardless of what command you send. Make sure you aren't reading part of a previous packet by mistake.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
alwaysnub
Posts: 20
Joined: Sat Aug 14, 2010 9:49 pm

Re: usb uhci IO-TD stalled

Post by alwaysnub »

No, thats not the problem. I'm setting the buffer data to 0 before each call to GetDeviceDescriptor and then dumping the contents to screen.

Here is the bytes returned when i call with a length of 18

Length: 109
DescriptorType: 4
24
195
0
85
1
2
0

That 109 Length sounds strange to say the least.
I'm currently working on a windows test app to see if windows produces the same result, and to see what it says.
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: usb uhci IO-TD stalled

Post by SpyderTL »

alwaysnub wrote:I'm currently working on a windows test app to see if windows produces the same result, and to see what it says.
Look for a utility called UsbTreeView. I use it to verify my USB descriptors in Windows.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
alwaysnub
Posts: 20
Joined: Sat Aug 14, 2010 9:49 pm

Re: usb uhci IO-TD stalled

Post by alwaysnub »

OK... Finally got everything working correctly.
First off, thanks for pointing me in the right directions, and for mentioning UsbTreeView (Big help).

The reason i was getting a return packet of 0 was because the first Data TD should have been Data Toggled (1/TRUE).
The data being returned when a length of 18 was specified, was not for an interface, but was actually the next 8 bytes of the Device Descriptor.
Apparently the controller can mix up the data if you don't do things the way it expects.
I also needed multiple data TD's when the length requested was over MaxPacketSize0, in this particular case (8).

Rules for building the transaction:
Setup TD Data-Toggle = 0
First Data TD Data-Toggle = 1 and alternates each Data TD.
Status TD Data-Toggle = 1
Don't forget to adjust the buffer pointer for each Data TD.

I welcome all feedback, if you think something should be changed, let me know.
Here is the modified code:

Code: Select all

PUHCI_TRANSFER_DESCRIPTOR AllocateTD(PUHCI_TRANSFER_DESCRIPTOR Next, USB_SPEED Speed)
{
	PUHCI_TRANSFER_DESCRIPTOR TD;

	TD = (PUHCI_TRANSFER_DESCRIPTOR) Malloc(sizeof(UHCI_TRANSFER_DESCRIPTOR));
	if (TD != 0)
	{
		MemSet(TD, 0, sizeof(UHCI_TRANSFER_DESCRIPTOR));
		if (Next == 0) TD->Next = BIT_T;
		else TD->Next = ((SIZE_PTR)Next & 0xFFFFFFF0) | BIT_Vf;
		TD->ErrorCounter = 3; // Stop after 3 errors.
		TD->Active = 1; // Execute This Transaction.
		if (Speed == USB_LOWSPEED) TD->LowSpeedDevice = TRUE;
	}

	return TD;
}

PUHCI_TRANSFER_DESCRIPTOR uhci_CreateTD_Setup(PUHCI_TRANSFER_DESCRIPTOR Next, PUSB_REQUEST Request, USB_SPEED Speed, BYTE Toggle, DWORD Device, BYTE Endpoint)
{
	PUHCI_TRANSFER_DESCRIPTOR TD;

	TD = AllocateTD(Next, Speed);
	if (TD != 0)
	{
		TD->PacketId = UHCI_TD_SETUP; // SETUP
		TD->MaxLength = 8 - 1; // Setup length is always 8
		TD->DataToggle = Toggle; // Should be toggled every list entry.
		TD->DeviceAddress = Device; // The device address.
		TD->Endpoint = Endpoint; // Endpoint number on the device serving as the data source or sink.
		TD->Buffer = (DWORD) Request; // USB Request info.
	}

	return TD;
}

PUHCI_TRANSFER_DESCRIPTOR uhci_CreateTD_IO(PUHCI_TRANSFER_DESCRIPTOR Next, USB_SPEED Speed, BYTE Direction, BYTE Toggle, WORD TokenBytes, DWORD Device, BYTE Endpoint, PVOID Buffer)
{
	PUHCI_TRANSFER_DESCRIPTOR TD;

	TD = AllocateTD(Next, Speed);
	if (TD != 0)
	{
		TD->PacketId = Direction; // UHCI_TD_IN or UHCI_TD_OUT
		if (TokenBytes != 0) TD->MaxLength = (TokenBytes - 1) & 0x7FF;
		else TD->MaxLength = 0x7FF; // Null data packet.
		TD->DataToggle = Toggle; // Should be toggled every list entry.
		TD->DeviceAddress = Device; // The device address.
		TD->Endpoint = Endpoint; // Endpoint number on the device serving as the data source or sink.
		TD->Buffer = (DWORD) Buffer; // Buffer to read or write.
	}

	return TD;
}

ERROR API uhci_ControlSet(PUSB_DEVICE_INFO UsbDevice, PUSB_REQUEST Request)
{
	PUHCI HC;
	PUHCI_TRANSFER_DESCRIPTOR SetupToken, HandshakeToken;
	ERROR Error;

	HC = (PUHCI) UsbDevice->Device->Controller;

	HandshakeToken = uhci_CreateTD_IO(0, UsbDevice->Speed, UHCI_TD_IN, TRUE, 0, UsbDevice->Address, 0, 0);
	SetupToken = uhci_CreateTD_Setup(HandshakeToken, Request, UsbDevice->Speed, FALSE, UsbDevice->Address, 0);

	uhci_SetupQH(HC->QH, SetupToken);

	// Run scheduler.
	OutW(HC->BAR + UHCI_FRNUM, 0);
	OutW(HC->BAR + UHCI_USBCMD, InW(HC->BAR + UHCI_USBCMD) | UHCI_CMD_RS);

	// Wait for completion.
	while ((SetupToken->Active == 1) || (HandshakeToken->Active == 1) && (HC->UsbIntError == FALSE));

	// Stop scheduler.
	OutW(HC->BAR + UHCI_USBCMD, InW(HC->BAR + UHCI_USBCMD) & ~UHCI_CMD_RS);

	// Wait for stop.
	while (!(InW(HC->BAR + UHCI_USBSTS) & UHCI_STS_HCHALTED));

	// Reset UHCI_STS_HCHALTED bit.
	OutW(HC->BAR + UHCI_USBSTS, UHCI_STS_HCHALTED);

	uhci_SetupQH(HC->QH, 0);

	if ((HandshakeToken->BitstuffError|SetupToken->BitstuffError) != 0) Error = ERROR_USB_BITSTUFF;
	else if ((HandshakeToken->DataBufferError|SetupToken->DataBufferError) != 0) Error = ERROR_USB_DATA_BUFFER;
	else if ((HandshakeToken->BabbleDetected|SetupToken->BabbleDetected) != 0) Error = ERROR_USB_BABBLE;
	else if ((HandshakeToken->CRC_TimeOutError|SetupToken->CRC_TimeOutError) != 0) Error = ERROR_USB_TIMEOUT;
	else if ((HandshakeToken->NakReceived|SetupToken->NakReceived) != 0) Error = ERROR_USB_NAK;
	else if ((HandshakeToken->Stalled|SetupToken->Stalled) != 0) Error = ERROR_USB_HALTED;
	else if (HC->UsbIntError == TRUE) Error = ERROR_USB_INTERRUPT;
	else Error = ERROR_NONE;

	Free(HandshakeToken);
	Free(SetupToken);

	return Error;
}

ERROR API uhci_ControlIn(PUSB_DEVICE_INFO UsbDevice, PVOID Buffer, PUSB_REQUEST Request)
{
	PUHCI HC;
	PUHCI_TRANSFER_DESCRIPTOR FirstToken, ThisToken, NextToken;
	WORD TotalLength, BytesPerPacket, TotalPackets, Offset, OddPacketLen, I;
	BYTE DataToggle, Active, BitstuffError, DataBufferError, BabbleDetected, CRC_TimeOutError, NakReceived, Stalled;
	ERROR Error;

	Offset = TotalLength = Request->Length;
	BytesPerPacket = UsbDevice->Descriptor.MaxPacketSize0;
	TotalPackets = TotalLength / BytesPerPacket;
	OddPacketLen = TotalLength - (TotalPackets*BytesPerPacket);
	FirstToken = 0;

	BitstuffError = DataBufferError = BabbleDetected = CRC_TimeOutError = NakReceived = Stalled = 0;

	HC = (PUHCI) UsbDevice->Device->Controller;

	FirstToken = uhci_CreateTD_IO(FirstToken, UsbDevice->Speed, UHCI_TD_OUT, TRUE, 0, UsbDevice->Address, 0, 0);
	if (OddPacketLen != 0)
	{
		Offset -= OddPacketLen;
		FirstToken = uhci_CreateTD_IO(FirstToken, UsbDevice->Speed, UHCI_TD_IN, FALSE, OddPacketLen, UsbDevice->Address, 0, (PBYTE)Buffer+Offset);
		I = 0;
	}
	else
	{
		Offset -= BytesPerPacket;
		FirstToken = uhci_CreateTD_IO(FirstToken, UsbDevice->Speed, UHCI_TD_IN, FALSE, BytesPerPacket, UsbDevice->Address, 0, (PBYTE)Buffer+Offset);
		I = 1;
	}
	for (; I < TotalPackets; I++)
	{
		Offset -= BytesPerPacket;
		FirstToken = uhci_CreateTD_IO(FirstToken, UsbDevice->Speed, UHCI_TD_IN, FALSE, BytesPerPacket, UsbDevice->Address, 0, (PBYTE)Buffer+Offset);
	}
	FirstToken = uhci_CreateTD_Setup(FirstToken, Request, UsbDevice->Speed, FALSE, UsbDevice->Address, 0);

	DataToggle = TRUE;
	ThisToken = (PUHCI_TRANSFER_DESCRIPTOR) (FirstToken->Next & 0xFFFFFFF1);
	while (((SIZE_PTR)ThisToken->Next & BIT_T) != BIT_T)
	{
		ThisToken->DataToggle = DataToggle;
		DataToggle ^= 1;
		ThisToken = (PUHCI_TRANSFER_DESCRIPTOR) (ThisToken->Next & 0xFFFFFFF1);
	}

	uhci_SetupQH(HC->QH, FirstToken);

	// Run scheduler.
	OutW(HC->BAR + UHCI_FRNUM, 0);
	OutW(HC->BAR + UHCI_USBCMD, InW(HC->BAR + UHCI_USBCMD) | UHCI_CMD_RS);

	while (TRUE) // Wait for completion.
	{
		Active = FALSE;
		ThisToken = FirstToken;
		while (((SIZE_PTR)ThisToken & BIT_T) != BIT_T)
		{
			Active |= ThisToken->Active;
			ThisToken = (PUHCI_TRANSFER_DESCRIPTOR) (ThisToken->Next & 0xFFFFFFF1);
		}
		if ((Active == FALSE) || (HC->UsbIntError == TRUE)) break;
	}

	// Stop scheduler.
	OutW(HC->BAR + UHCI_USBCMD, InW(HC->BAR + UHCI_USBCMD) & ~UHCI_CMD_RS);

	// Wait for stop.
	while (!(InW(HC->BAR + UHCI_USBSTS) & UHCI_STS_HCHALTED));

	// Reset UHCI_STS_HCHALTED bit.
	OutW(HC->BAR + UHCI_USBSTS, UHCI_STS_HCHALTED);

	uhci_SetupQH(HC->QH, 0);

	NextToken = ThisToken = FirstToken;
	while (((SIZE_PTR)NextToken & BIT_T) != BIT_T)
	{
		ThisToken = NextToken;
		BitstuffError |= ThisToken->BitstuffError;
		DataBufferError |= ThisToken->DataBufferError;
		BabbleDetected |= ThisToken->BabbleDetected;
		CRC_TimeOutError |= ThisToken->CRC_TimeOutError;
		NakReceived |= ThisToken->NakReceived;
		Stalled |= ThisToken->Stalled;
		NextToken = (PUHCI_TRANSFER_DESCRIPTOR) (ThisToken->Next & 0xFFFFFFF1);
		Free(ThisToken);
	}

	if (BitstuffError != 0) Error = ERROR_USB_BITSTUFF;
	else if (DataBufferError != 0) Error = ERROR_USB_DATA_BUFFER;
	else if (BabbleDetected != 0) Error = ERROR_USB_BABBLE;
	else if (CRC_TimeOutError != 0) Error = ERROR_USB_TIMEOUT;
	else if (NakReceived != 0) Error = ERROR_USB_NAK;
	else if (Stalled != 0) Error = ERROR_USB_HALTED;
	else if (HC->UsbIntError == TRUE) Error = ERROR_USB_INTERRUPT;
	else Error = ERROR_NONE;

	return Error;
}
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: usb uhci IO-TD stalled

Post by SpyderTL »

I haven't started on my UHCI code, yet. But the OHCI has the option for the controller to keep up with the data toggle for you. I had issues until I decided to let the controller handle it.

Not sure if there is something similar in UHCI.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
alwaysnub
Posts: 20
Joined: Sat Aug 14, 2010 9:49 pm

Re: usb uhci IO-TD stalled

Post by alwaysnub »

the OHCI has the option for the controller to keep up with the data toggle for you. I had issues until I decided to let the controller handle it.
I did not know that, thinks for the info, I'll be starting on my OHCI code very soon.
Not sure if there is something similar in UHCI.
No, not that iv seen, and iv been through the specification pretty thoroughly.

I would just port my code or use it as an example, because it works beautifully right now.
I can set the Device Address, get the Device Descriptor and get the Configuration Descriptors without any problems.
alwaysnub
Posts: 20
Joined: Sat Aug 14, 2010 9:49 pm

Re: usb uhci IO-TD stalled

Post by alwaysnub »

I have found a bug in this code.

The scheduler/controller is being stopped after a transaction, this can cause problems for HID devices!
These lines should be removed:

Code: Select all

// Stop scheduler.
OutW(HC->BAR + UHCI_USBCMD, InW(HC->BAR + UHCI_USBCMD) & ~UHCI_CMD_RS);

// Wait for stop.
while (!(InW(HC->BAR + UHCI_USBSTS) & UHCI_STS_HCHALTED));

// Reset UHCI_STS_HCHALTED bit.
OutW(HC->BAR + UHCI_USBSTS, UHCI_STS_HCHALTED);
In these functions:

uhci_ControlSet
uhci_ControlIn
Post Reply