Digging through USB
USB in raspberry is one of the least documented things in this awesome machine. Apart from the source code contributed by Synopsys to the Linux kernel and some derivates of it (for example in u-boot), there are not so much really free sources of documentation and/or code. But hey, source code shall be the best documentation, right?

I've spent last week on the USB code for AROS. I've been learning the old code, trying to understand it as well as trying to understand how Poseidon (our USB stack) drivers are working. At the same time I was learning about the DesignWare OTG core used in Raspberry as much as possible. It turned out we already had some basic OTG initialisation code which I have improved a little. Around last weekend I came to a point where I was putting the USB port online and hoped to initiate any kind of transmission. Well, no luck. All I got were interrupts telling me that the transmission channel was closed, data was sent but there was no reply from the device. Strange.

The reason was, as always, pretty simple. Every USB driver acts as an USB hub as well in order to let Poseidon control the state of USB ports. The code there was reading status of the only USB port in Raspberry's CPU but when changing the status it erroneously deleted some of the status bits, including the port enable one. It was so because those bits in the status register are of a type Read/WriteToClear. It means, if one does not want to change their value from 1 back to 0, one has to actually write the 0 value. Very practical thing e.g. in interrupt handlers, where one reads the interrupt status register to learn what was the interrupt reason, and writes it back to the same register in order to clear the interrupts. 

After fixing that code it turned out that the communication was still unsuccessful. Apparently the USB device was not understanding the host for some reason. That should not happen since the request sent was one of the standard ones implemented by virtually anything with an USB connector. That was my fault, of course. I assumed that Poseidon clears the data caches before forwarding the work to the USB drivers. I was mistaken of course since that's the responsibility of the driver itself. After fixing it there was...

Party time!

The USB device responded and acknowledged the transmission! Yay! Awesome! But why were all the request sent after address change failing with timeout? They should not. Once again, address set is supported just by anything. Out of curiosity I have tried to contact the device at address 0 once again and there it was, still responding properly. The enlightenment came. The bus address for DMA transmissions was, as it is in many bare metal USB implementations, just the pure memory address of the buffer as seen by the ARM cpu. Wrong again, I have "prefixed" it with the real location of uncached RAM and booted AROS once again.

I saw this:

Product     : Hub: Vdr=0424/PID=9514
Manufacturer: Standard Microsystems Corp.
SerialNumber: n/a
/Users/michal/git/AROS/rom/usb/poseidon/./poseidon.library.c:psd_20_psdEnumerateDevice/3092: USBVersion: 0200
Class     : 9
SubClass  : 0
DevProto  : 2
VendorID  : 1060
ProductID : 38164
DevVers   : 0200

and this:

Product     : Vendor: Vdr=0424/PID=EC00
Manufacturer: Standard Microsystems Corp.
SerialNumber: n/a
/Users/michal/git/AROS/rom/usb/poseidon/./poseidon.library.c:psd_20_psdEnumerateDevice/3092: USBVersion: 0200
Class     : 255
SubClass  : 0
DevProto  : 1
VendorID  : 1060
ProductID : 60416
DevVers   : 0200

and even this:

Product     : Hub: Vdr=0424/PID=9514
Manufacturer: Standard Microsystems Corp.
SerialNumber: n/a
/Users/michal/git/AROS/rom/usb/poseidon/./poseidon.library.c:psd_20_psdEnumerateDevice/3092: USBVersion: 0200
Class     : 9
SubClass  : 0
DevProto  : 2
VendorID  : 1060
ProductID : 38164
DevVers   : 0200

What are these things? The first one is USB hub built in the Raspberry. Thanks to this one the Pi machines (with exception of Pi0 and computing modules) have more than just one single USB port. The second one is the network chip in raspberry, the third one is my USB SD card reader which I have just connected to see what happens. AROS tried, of course, to boot from it ;)

So, the first step towards working USB is done. The control transfers are working as you can see above. Next step is to implement bulk and interrupt transfers, which should be relatively easy now when I have the basics in control. Finally some error handling will be added and USB for Pi will be as complete as the PC version is. Once this milestone is reached I will think about releasing some binaries to let you play with.

Tier Benefits
Recent Posts