Alrght, after a few weeks of nothing I finally got around to write a blog post again
This time I'm going to explain how I managed to get SDHC cards to work with the Wii's internal slot without requiring any patches to the IOS.
This front slot is normally accessed by the device node /dev/sdio/slot0 which directly talks to the hardware registers of a standard sd host controller - there is even a specification you can download and read that explains everything you need.
However, to simplify things a bit nintendo apparently thought that it would be a good idea to let the IOS handle the SD card initialization process which basically only consists of sending three commands to the SD card to get it into the right state. Next to those commands it also pokes some host controller registers in order to enable the power supply, setup a stable clock and enable some interrupts. Those things are basically everything needed to get the host controller and the SD card to a state at which it accepts just about every command - and this is were IOS stops its work. It pokes another memory location that allows the powerpc to directly send commands to the SD card by either using a ioctl for normal commands or a ioctlv for data commands, i.e. commands that require data to be transferred using DMA. The powerpc has to take care of the rest and send the SELECT and (MULTIPLE_)BLOCK_READ commands to actually read data from the card. This seems to be their idea of abstraction...
When you now insert a SDHC card and call IOS' reset function it just returns some error value: SDHC cards have a slightly different initialization process: After sending the "GO_IDLE_STATE" command you need to send another command to indicate that you know about SDHC and are going to use it. The next two commands are then very similar to the SDv1 initialization with one more bit set to tell the card (again) that you know about high-capacity cards. If you don't send the special "i know about sdhc kthx" (aka CMD8) command the card will just return an error when you send the next command because it thinks that it can't be used with this host.
Since the SDv1 and the SDv2 (SDHC) process is nicely documented in the SD host controller and the physical layer specifications it sounds like it would be trivial to just do it yourself on the powerpc. There are however two things that you'll have to take care of:
At first IOS won't allow you to just send commands to the SD card if you didn't successfully call the reset ioctl first.
The second problem is that the card does neither get power nor a clock and all interrupts - which are required for the sdi driver to fully work - are disabled before you called reset
Fixing the first issue seems to be impossible at the first look without a IOS patch because of the following check inside the driver that fails when the card wasn't initialized:
default_sd_command ; CODE XREF: sdi_main+4E0jBL do_something_init_maybeLDR R0, [R6,#8]MOVS R3, #0x84 ; 'ä'ADDS R2, R0, #0MULS R2, R3LDR R3, =sdi_structsADDS R1, R2, R3LDR R2, [R1,#sdi_struct.card_present_state]LDR R3, =0xFFFF0000TST R2, R3BNE default_sd_command_checks_passed ; only branch if "card initialized" bit is setLDR R7, =0xC1000004 ; error codeADDS R5, R7, #0STR R0, [SP,#0x68+var_4C]B ioctl_return_maybe
Patching this check out would be quite easy - just replace the BNE to default_sd_command_checks_passed with an unconditional branch to it. The problem is that this would force everyone wanting to use SDHC cards on his Wii to install a hacked IOS.
But after I took a look at something different I found a way to still send commands to the card: The code listed above is just present in the ioctl handler - the ioctlv handler doesn't do this check. It just checks the passed vectors and calls the do_send_command function that the ioctl also calls then. This gives use a simple way to just send commands even before the reset ioctl was called to the SD card: Just use the ioctlv and pass a NULL buffer with a 0 length and a block count of zero. do_send_command checks for those values and just thinks that you actually send a ioctl instead of an ioctlv and will happily send your command to the sd card because both ipc messages use the same function to handle the card commands (which just sets some registers and memory locations up and lets the interrupt handler do the rest then).
There still is one problem though: The SD card neither gets power nor has a stable clock yet while both are required to answer to commands and the interrupts in the host controller are still all disabled which would make commands fail too. But well, there also is a way around this when you take a look at the ioctls the driver provides. Especially the set_hcreg and the get_hcreg commands are interesting: They directly allow the powerpc to write to the sd host controller hardware registers. Together with its specification it is pretty simple to enable the power supply, give the card a stable clock and enable interrupts.
By 'abusing' those two solutions and reading the simplified physical layer specification it was simple to do the card initialization on the powerpc by just patching the wiisd.c code of libogc a bit. The only thing you need to do to enable SDHC support for your homebrew is to fetch the latest libogc which already contains the patches and recompile it. libfat will automagically work then without any changes to your code
It looks as if some cards are not working with this approach yet. I'm pretty sure that this just is a timeout issue. Please come to #wiidev or #hackmii at EFNet and poke me there so that we can debug the problem together and hopefully fix it. It would be really great if you even have a usb gecko because that facilitates things a lot. You'll probably have to read debug prints on your TV otherwise.