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;
}