I've (finally) been able to create a patch for libogc today which just got accepted and adds my usb-storage code to it - just wait for the next release or get the CVS version if you know what you are doing. Thanks again to shagkur for some miscellaneous fixes and hints to my code.
Since my last posts even more devices are working now and only a few ones are not working which I'm unable to fix because the owners either didn't give me a usb log or because that device is just stupid and doesn't confirm to the usb storage protocol in a *really* bad way. If you want these devices to work get me a full usb transfer log while you're connecting your device to you computer. Just reporting that device $whatever is not working with the output of my old test applications will not help me to fix this drive, sorry.
However, I'll first talk in this post about why someone screwed up the IOS USB driver and what evil hack fixes this and then about how to use my usb-storage code.
Let's start with the IOS USB driver: It provides functions to get a device list, setup callbacks for device insertion/removal, open/close devices and send/read bulk, control and interrupt messages from/to them. At the first sight this looks just like libusb which should be enough for all kind of devices you want to connect. However, once you take a closer look to the functions you'll notice that there in fact is one difference: The IOS functions do not support timeouts and block until the device sends or receives the requested amount of data. So what happens now when you want to receive data from a USB device that doesn't want to send data to you? Your function will block forever because the device doesn't send data to the IOS and you can't handle that error case by - for example - resetting the device. I talked with marcan about this and he suggested me to use asynchronous IOS functions and just close the device handle when I don't want to wait anymore for the request to complete. This should be working in most cases but isobel - who is the main author of the wii-linux kernel patch set - said that you'll sometimes need to reboot(!) IOS, which will screw up all currently opened handles in your application and clean large parts of MEM2, in order to make such calls return. This is definitely not possible to do for a support library and I didn't encounter such an issue while writing my usb-storage code so I hope that such things will not happen when it is used. This IOS_IoctlvAsync hack is not really nice but it's currently the only solution to fix functions blocking forever and making the whole application unusable. We can just hope that those problems will be fixed in an upcoming IOS update.
I'm currently returning the error code USBSTORAGE_ETIMEDOUT in such cases which will mean that the device handle is no longer usable and you'll need to redo the whole initialization process and hope that this will not happen again. Get me some usb logs or debug my usb-storage code with a USB gecko and tell me where it fails and I might be able to fix this.
But let's talk about the usage of my code which is still missing some documentation in the header files - I'll add this when I'm really bored the next time
Before starting to use the usb-storage code you'll need to initialize the USB subsystems and my storage code by calling the following two functions. This is needed because the usb-storage code is obviously based on the USB subsystems which needs a IOS heap just like my code:
USB_Initialize();
USBStorage_Initialize();
You should probably also check return values here as both might fail when no more memory/no new heap id is currently available.
Afterwards you should use USBStorage_GetMaxLUN() to get number of logical units your device supports. On most USB sticks and hard discs there will only be one but card readers will most likely report multiple LUN. The next step is to prepare each unit you want to access by calling USBStorage_MountLUN(lun);. It will basically check the device for any errors and prepare it for reading and writing which is the next step: You just use USBStorage_Read() or *_Write() in order to read or write to your drive's sectors. That's it
There are some more functions but those are mostly self-explaining and probably won't even be needed by most applications.
Oh, and just in case you didn't get it yet: The "1.1" in the topic does mean that only USB 1.1 is supported.
I'll also destroy some conspiracy theories here that were mainly created on some spanish board and some other one which has the name of a last-generation handheld in its title:
I have done some tests with the IOS on USB2 support and I'm pretty sure that it's not supported. I cannot do anything against this and I didn't intentionally limit my code to USB 1.1. However, you still wouldn't get your ISO loader even if hi-speed USB 2 data transfers would be possible because it requires an immense amount of work on either patching game executables or the IOS which will most likely not be done very soon. I'd really like to have USB 2 support too but it's currently not possible :/
Thanks again (in no particular order) to marcan, shagkur, dhewg (who all helped my with some problems) and all those people who helped me by testing their devices and reporting any errors they found!
And one appeal to all those homebrew developers out there who now want to add this code to their favorite emulator: Please just work together with the current "main" author of the emulator and don't release any versions of your own (which I've done myself once in the past) - this will just create a huge mess and will not help anyone in the end - working together with the main author definitely is the best solution even if all those annoying users will have to wait one or two weeks more for their release then