Friday, January 7, 2011

Proper USB Storage and SD(HC) Handling in C for Wii Homebrew

Handling File IO is another popular topic in Wii Hombrew for obvious reasons and one that I've spent a significant amount of time on. I'm going to use this post demonstrate proper initialization and deinitialization of SD(HC) and USB devices in C. There are in fact quite a few different ways to do it but I've refined my personal methodology over years of carefully tweaking it and testing it in many apps.

I'm going to walk through initializing and deinitializing both devices since you probably want to use both as a developer.

So the first thing that needs to be done is to include libfat. To do this add to your header:
#include (sdcard.h/wiisd_io.h)
#include (fat.h)
 
Then add -lfat under LIBS: in your makefile.

Now let's read some code. These are functions for how I initialize and deinitialize the SD(HC) device plugged in:

void InitSD(){
 
fatUnmount("sd:/");
__io_wiisd.shutdown();
fatMountSimple("sd", &__io_wiisd);  
 
}
 
void DeInitSD() {
 
fatUnmount("sd:/");
__io_wiisd.shutdown() 
 

These are functions for how I initialize and deinitialize the USB Storage device plugged in:

void InitUSB(){
 
fatUnmount("usb:/"); 
bool isMounted = fatMountSimple("usb", &__io_usbstorage);
 
if(!isMounted){
 
fatUnmount("usb:/");
fatMountSimple("usb", &__io_usbstorage);
 
bool isInserted = __io_usbstorage.isInserted();
 
if(isInserted) {
 
int retry = 10;
 
while(retry) { 
 
isMounted = fatMountSimple("usb", &__io_usbstorage);
if (isMounted) break;
sleep(1);
retry--;
 
}
         

void DeInitUSB() {

fatUnmount("usb:/");
__io_usbstorage.shutdown(); 

}

A quick note on the USB code is that it looks startlingly simple compared to what others do and that I've actually never seen it fail on any USB Storage device (so long as it's formatted to NTFS or fat32 of course). I'm always trying to improve my code however so please feel free to pitch suggestions my way. Alternatively, sven from Team Twiizers has written an excellent USB Storage driver in C (a copy of it can be found here) which offers many additional functions aside from just initializing and deinitializing the USB Storage device.

C++ developers can grab a copy of my DOP-Mii Library which provides an excellent wrapper for initializing and deinitializing these storage devices as well as a few additional functions which work as wrappers for some of sven's USB Storage functions.

As always I hoped this helped out a fellow dev. Always feel free to leave questions in the comments below or in my inbox at castlevania7689@yahoo.com

26 comments:

  1. The copy of usbstorage.c you linked to is out of date and contains a few bugs that have since been fixed in libogc (it was also written by several other people apart from svpe). You're missing "#include (ogc/usbstorage.h)" with your other 2 includes. The fatUnmount calls should not contain the trailing slash after the device name, only the colon.

    ReplyDelete
  2. Excellent advice thanks. If you could give me the link to an updated copy of the usbstorage.c file I would really appreciate it (and btw svpe is the only one listed in the license so I was just assuming). The code actually compiles for me without the "#include (ogc/usbstorage.h)" (on the latest official libogc release at least). And the fat unmount calls work despite the trailing slash unless there's something in the SVN since the last libogc release which has changed that; I actually don't know of any source out there that just uses the colon. I did forget that I could put __io_usbstorage.shutdown(); in USBDeinit() though. This may change the need to include the usbstorage header, I'll investigate tomorrow. Thanks again.

    ReplyDelete
  3. usbstorage.c is part of libogc: http://devkitpro.svn.sourceforge.net/viewvc/devkitpro/trunk/libogc/libogc/usbstorage.c

    As for the fatUnmount issue, it doesn't return a value so there's no way you could be sure it works. See http://code.google.com/p/snes9x-gx/source/browse/trunk/source/fileop.cpp?r=660#200 for the correct usage.

    ReplyDelete
  4. Thanks for posting stuff like this. It's crazy how much I've learned from reading guys like you and tantric.

    ReplyDelete
  5. Thanks for the updated usbstorage.c file. It was passed onto me a long time ago and I actually didn't even know it originated in libogc o_0. Also, turns out that __io_usbstorage.shutdown() can also be called without including ogc/usbstorage.h so I added it to my deinit function and I am still refraining from including that file. Also, I tested fopen calls after mounting with and without the slash and they worked. I then tested fopen calls after unmounting with and without the slash and they failed. I don't know if there is a right or a wrong way to do it, but they both work and I've always used the slash so I think I will stick to it for now. Thanks again for the advice and assistance.

    And welcome Ari and ketufe :)

    ReplyDelete
  6. Oh wonderful, gccore.h #includes "ogc/usbstorage.h" (so it's included by default) but not "sdcard/wiisd_io.h". I guess that makes about as much sense as putting wiisd_io.h in the sdcard directory, seeing as all the other files in there are for the sdgecko.

    With the fatUnmount thing, I dug into devkitpro to find the newlib patch that handles it. A copy of the function where the name is checked is here: http://pastie.org/1445018
    Since it uses strncmp to check against the registered device name you can actually append anything you want after the colon in the string passed to fatUnmount and it will still find+unmount properly. The bizarre thing however is if you forget the colon it will happily unmount your defaultDevice - which may not be the one you intended at all!

    ReplyDelete
  7. Hey Arikado, anything post worthy about Desmumewii.??

    Thanks ;)

    ReplyDelete
  8. ....and RealityBoy Wii,please.:-)

    ReplyDelete
  9. I doubt you'll hear much more from me on either fronts until summer rolls around unless the other devs get back in gear. On desmume I've made a lot of progress fixing more endianness issues and optimizing code for some significant performance boosts. I'd throw it in the SVN if parts of it weren't so terribly unstable right now :s For Reality Boy I need to port more of ALLEGRO and I'm basically working on both of those alone :x Unless I find more devs or the other devs start really cranking I'm forced to focus on coding for school and my job for a bit now. I still want to finish DOOM, Hexen, Heretic, Strife, and something else before summer though since they're really small easy projects and a lot of fun to play with. If I could just get a free weekend ...

    ReplyDelete
  10. Hey Arikado, is there anything worthy about the nulldc for wii???

    ReplyDelete
  11. Thanks for your answer,Arikado!
    I am a little sad,because these two emulators are my most anticipated homebrew releases this year,but everything great needs time!
    I wish you an even better and more productive year,you deserve it! :-)

    ReplyDelete
  12. I'm not really involved in nulldce anymore. They're moving faster than I can keep up with them. I did write a nice chunk of code and did a little advising but I don't have the time to work on it anymore. Don't worry, it's in far better hands than mine ;-)

    ReplyDelete
  13. thanks Arikado
    i anticipated all the time, you guys put in the nulldce for the wii. i just hope gunlet legends works, or just playable.
    i also wanted to ask, can you explain to me how to make a game for the homebrew channel.

    ReplyDelete
  14. I'm actually writing several tutorials on porting, game development (with libwiisprite of course!), and savegame exploitation to coincide with new software releases and help me bide my time while still be somewhat involved in Wii homebrew. Stay tuned ;)

    ReplyDelete
  15. will libwiisprite help me make a fighting game?

    ReplyDelete
  16. Only if you want a strictly 2D fighting game (though iirc AerialX used it with 3D graphics a long time ago).

    ReplyDelete
  17. yeah i wana make a 2d fighting game, and its gonna be super big i think when its finished it just might be the biggest game on the homebrew channel, but idk how to make it..

    ReplyDelete
  18. but how do i make it???

    ReplyDelete
  19. Hey Arikado, hows things coming along, any progress being made on desmumewii??

    ReplyDelete
  20. ^^^
    I was just wondering this myself. There hasn't been an update in a while...

    (NOT THAT I'M RUSHING YOU OR ANYTHING)

    ReplyDelete
  21. Arikado has been busy with school (among other things) and hasn't been working on Wii projects.

    ReplyDelete
  22. Okay, that works. A little update every once in a while is nice, even if it isn't necessarily what we want to hear.

    ReplyDelete
  23. thank you so much for this post. it will really help wii users. :)

    ReplyDelete
  24. In the InitUSB() function the fatMountSimple could be called twice without unmounting the device first. Could be this a problem?

    if(!isMounted){
    fatUnmount("usb:/");

    fatMountSimple("usb", &__io_usbstorage);

    bool isInserted = __io_usbstorage.isInserted();
    if(isInserted) { int retry = 10; while(retry) {

    isMounted = fatMountSimple("usb", &__io_usbstorage);

    ReplyDelete