mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
fusee: add support for SDMMC write operations
This commit is contained in:
parent
553cd236f2
commit
2e362d93da
2 changed files with 102 additions and 1 deletions
|
@ -241,6 +241,8 @@ enum sdmmc_command {
|
|||
CMD_SET_BLKLEN = 16,
|
||||
CMD_READ_SINGLE_BLOCK = 17,
|
||||
CMD_READ_MULTIPLE_BLOCK = 18,
|
||||
CMD_WRITE_SINGLE_BLOCK = 24,
|
||||
CMD_WRITE_MULTIPLE_BLOCK = 25,
|
||||
|
||||
CMD_APP_SEND_OP_COND = 41,
|
||||
CMD_APP_COMMAND = 55,
|
||||
|
@ -473,6 +475,10 @@ static const char *sdmmc_get_command_string(enum sdmmc_command command)
|
|||
return "CMD_APP_COMMAND";
|
||||
case CMD_APP_SEND_OP_COND:
|
||||
return "CMD_APP_SEND_OP_COND";
|
||||
case CMD_WRITE_SINGLE_BLOCK:
|
||||
return "CMD_WRITE_SINGLE_BLOCK";
|
||||
case CMD_WRITE_MULTIPLE_BLOCK:
|
||||
return "CMD_WRITE_MULTIPLE_BLOCK";
|
||||
|
||||
// For commands with low numbers, read them string from the relevant array.
|
||||
default:
|
||||
|
@ -2242,6 +2248,9 @@ int sdmmc_init(struct mmc *mmc, enum sdmmc_controller controller)
|
|||
// Use DMA, by default.
|
||||
mmc->use_dma = true;
|
||||
|
||||
// Don't allow writing unless the caller explicitly enables it.
|
||||
mmc->write_enable = SDMMC_WRITE_DISABLED;
|
||||
|
||||
// Default to relative address of zero.
|
||||
mmc->relative_address = 0;
|
||||
|
||||
|
@ -2297,7 +2306,7 @@ int sdmmc_select_partition(struct mmc *mmc, enum sdmmc_partition partition)
|
|||
|
||||
|
||||
/**
|
||||
* Reads a sector or sectors from a given SD card.
|
||||
* Reads a sector or sectors from a given SD/MMC card.
|
||||
*
|
||||
* @param mmc The MMC device to work with.
|
||||
* @param buffer The output buffer to target.
|
||||
|
@ -2323,6 +2332,62 @@ int sdmmc_read(struct mmc *mmc, void *buffer, uint32_t block, unsigned int count
|
|||
return sdmmc_send_command(mmc, command, MMC_RESPONSE_LEN48, MMC_CHECKS_ALL, extent, NULL, count, false, count > 1, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the SDMMC write lockout, enabling access to the card.
|
||||
* Note that by default, setting this to WRITE_ENABLED will not allow access to eMMC.
|
||||
* Check the source for a third constant that can be used to enable eMMC writes.
|
||||
*
|
||||
* @param perms The permissions to apply-- typically WRITE_DISABLED or WRITE_ENABLED.
|
||||
*/
|
||||
void sdmmc_set_write_enable(struct mmc *mmc, enum sdmmc_write_permission perms)
|
||||
{
|
||||
mmc->write_enable = perms;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes a sector or sectors to a given SD/MMC card.
|
||||
*
|
||||
* @param mmc The MMC device to work with.
|
||||
* @param buffer The input buffer to write.
|
||||
* @param block The sector number to write from.
|
||||
* @param count The number of sectors to write.
|
||||
*
|
||||
* @return 0 on success, or an error code on failure.
|
||||
*/
|
||||
int sdmmc_write(struct mmc *mmc, void *buffer, uint32_t block, unsigned int count)
|
||||
{
|
||||
// Sanity check variables: we're especially careful about allowing writes to the switch eMMC.
|
||||
bool is_emmc = (mmc->controller == SWITCH_EMMC);
|
||||
bool allow_mmc_write = (mmc->write_enable == SDMMC_WRITE_ENABLED_INCLUDING_EMMC);
|
||||
|
||||
uint32_t command = (count == 1) ? CMD_WRITE_SINGLE_BLOCK : CMD_WRITE_MULTIPLE_BLOCK;
|
||||
|
||||
// Determine the argument, which indicates which address we're reading/writing.
|
||||
uint32_t extent = block;
|
||||
|
||||
// If we don't have an explict write enable, don't allow writes.
|
||||
if (mmc->write_enable == SDMMC_WRITE_DISABLED) {
|
||||
mmc_print(mmc, "tried to write to an external card, but write was not enabled!");
|
||||
return EACCES;
|
||||
}
|
||||
|
||||
// Explicitly protect the switch's eMMC to prevent bricks.
|
||||
if (is_emmc && !allow_mmc_write) {
|
||||
mmc_print(mmc, "cowardly refusing to write to the switch's eMMMC");
|
||||
return EACCES;
|
||||
}
|
||||
|
||||
// If this card uses byte addressing rather than sector addressing,
|
||||
// multiply by the block size.
|
||||
if (!mmc->uses_block_addressing) {
|
||||
extent *= sdmmc_get_block_size(mmc, false);
|
||||
}
|
||||
|
||||
// Execute the relevant read.
|
||||
return sdmmc_send_command(mmc, command, MMC_RESPONSE_LEN48, MMC_CHECKS_ALL, extent, NULL, count, true, count > 1, buffer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks to see whether an SD card is present.
|
||||
|
|
|
@ -71,6 +71,18 @@ enum sdmmc_controller {
|
|||
SWITCH_EMMC = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Write permission modes for SD cards.
|
||||
*/
|
||||
enum sdmmc_write_permission {
|
||||
SDMMC_WRITE_DISABLED,
|
||||
SDMMC_WRITE_ENABLED,
|
||||
|
||||
/* use this with the utmost caution so you don't wind up with a brick */
|
||||
SDMMC_WRITE_ENABLED_INCLUDING_EMMC,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Primary data structure describing a Fusée MMC driver.
|
||||
|
@ -83,6 +95,7 @@ struct mmc {
|
|||
unsigned int timeout;
|
||||
enum sdmmc_card_type card_type;
|
||||
bool use_dma;
|
||||
enum sdmmc_write_permission write_enable;
|
||||
|
||||
/* Card properties */
|
||||
uint8_t cid[15];
|
||||
|
@ -164,6 +177,29 @@ int sdmmc_select_partition(struct mmc *mmc, enum sdmmc_partition partition);
|
|||
int sdmmc_read(struct mmc *mmc, void *buffer, uint32_t sector, unsigned int count);
|
||||
|
||||
|
||||
/**
|
||||
* Releases the SDMMC write lockout, enabling access to the card.
|
||||
* Note that by default, setting this to WRITE_ENABLED will not allow access to eMMC.
|
||||
* Check the source for a third constant that can be used to enable eMMC writes.
|
||||
*
|
||||
* @param perms The permissions to apply-- typically WRITE_DISABLED or WRITE_ENABLED.
|
||||
*/
|
||||
void sdmmc_set_write_enable(struct mmc *mmc, enum sdmmc_write_permission perms);
|
||||
|
||||
|
||||
/**
|
||||
* Writes a sector or sectors to a given SD/MMC card.
|
||||
*
|
||||
* @param mmc The MMC device to work with.
|
||||
* @param buffer The input buffer to write.
|
||||
* @param block The sector number to write from.
|
||||
* @param count The number of sectors to write.
|
||||
*
|
||||
* @return 0 on success, or an error code on failure.
|
||||
*/
|
||||
int sdmmc_write(struct mmc *mmc, void *buffer, uint32_t block, unsigned int count);
|
||||
|
||||
|
||||
/**
|
||||
* Checks to see whether an SD card is present.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue