Hi there,
working on a ring0 singletask RTOS I have encountered an annoying problem regarding an USB UHCI controller. Testing board is an Intel Atom board D410PT with 1 EHCI and 4 UHCI companion controllers in the NM10 chipset.
I can send packets to a function, but responding IN packets from the function are ignored. The SETUP packet of the get_device_descriptor() arrives in the function, which then replies with the usual 18 bytes, but UHCI hardware sets the IN transfer descriptor as if nothing would have been sent back (C_ERR runs out and the CRC/Timeout bit is set in the status-field) . I analysed the actual USB data flow by controling the function's source code (on a SiLabs C8051F320 development kit) which works fine with Windows, Mac and Linux. Also the EHCI on the Atom board works fine!
After 2 weeks of searching this error I don't have any ideas left what else to try!
Here the details:
As USB-function I'm using a SiLabs C8051F320DK evaluation board, where I have programmed 2 LEDs to go ON when the GET_DEVICE_DESCRIPTOR has been received and the SET_ADDRESS control transfer has been accomplished. The function has been tested and works fine with Windows XP, Suse Linux and on a Mac.
When booting my Atom Board (D410PT), the BIOS enumerates the function (both LEDs go ON), thus the hardware on my board works perfectly. (BIOS-version is MOPNV10N.86A.0178.2010.0331.0947)
The NM10 chipset of the board includes 1 EHCI with 4 UHCI companion controllers for full- and low-speed transfers.
After my kernel has started, the following is setup (in sequence) for USB usage:
- set the PCI bus master enable and memory space enable bits (if necessary)
- get Host Control Capabilities Register address from PCI (that is EHCI at D29:F7 !)
- check if the BIOS controls the EHCI and set control to OS. This regards bits 16 and 24 of the USB EHCI Legacy Support Extended register (offset 0x68). After this, the BIOS is not more able to enum the USB-function.
- get ehci mem space size, get Host Control Operational Register address and reset the EHCI.
- Next I allocate memory for EHCI and UHCI queues and setup 3 framelists, 1 for EHCI use, and 2 for 2 UHCI controllers (there are 4, but only 2 will be used).
- Register CONFIGFLAG is setup to route all ports to the EHCI first
- The I/O addresses for the 4 UHCI controller are taken from PCI Baseaddress Register (D29:F0/F1/F2/F3) at offset 0x20
- Every UHCI controller is now:
- stopped and globally reset
- clear all interrupt- and error-bits (register STS is ANDed with 0x1F)
- clear legacy support and detach UHCI from BIOS by writing 0x8F00 to the PCI register USB_LEGKEY at offset 0xC0
- start HCRESET (CMD |= 2) and wait till reset has finished
- USB registers are cleared (CMD, STS, INTR, FRNUM and PORTSC[0/1] are 0, SOFMOD is 0x40)
At this point I start scanning the 8 ports for attached devices (to easy testing, only 1 device is attached!). If a high-speed device is found, everything runs fine, no problem!
If a full-speed device is found (EHCI port-reset leaves port disabled, ergo it must be full- or low-speed), the following occurs:
- I release port ownership to a companion host controller by setting EHCI_PORTSC[port] |= (1<<13) and wait for the change to be accomplished
- Store the frame list base address to the UHCI FRBASEADD register and set FRNUM to 0
- I set bit PIRQ by writing 0x2000 to the PCI register USB_LEGKEY at offset 0xC0 (enable USB-PCI interrupt, BUT: All is still done by polling, no interrupts are enabled!)
- I send a resume signal on USB for 20 ms
- I reset the connected port
- I start the UHCI controller with max packet size to 64 bytes. (The last 3 items can be exchanged in any manner, the result is allways the same!)
Now I start enumeration by invoking the get_device_descriptor transaction. The 8 bytes of the SETUP token are sent and recived by the function (LED1 goes ON) which replies with the 18 requested bytes of the descriptor. UHCI controller runs out of CERR and returns a CRC/timeout error.
Here the queue transfer definitions with the data before and after transfer:
1st Transfer: Setup: After Transfer:
Link pointer: 0xDEAD0001 0x1EFBFBF4
Control/Status: 0x18800000 0x18000007
Token: 0x00E0002D 0x00E0002D
buffer: 0x0009FB60 0x0009FB60
2nd Transfer:
Link pointer: 0x1EFBFC14 0x1EFBFC14
Control/Status: 0x18800000 0x004507FF <--- here the error shows up!!!
Token: 0x02240069 0x02240069
buffer: 0x0009FB70 0x0009FB70
3rd Transfer is irrelevant because it has never been arrived there!
Is anybody out there able to give me any hint???
Dispaired and Hopefully,
Michael