libdragon
|
Managed mempak interface. More...
Data Structures | |
struct | entry_structure |
Structure representing a save entry in a mempak. More... | |
Files | |
file | mempak.c |
Mempak Filesystem Routine. | |
file | mempak.h |
Mempak Filesystem Routines. | |
Defines | |
#define | MEMPAK_BLOCK_SIZE 256 |
Size in bytes of a Mempak block. | |
Typedefs | |
typedef struct entry_structure | entry_structure_t |
Structure representing a save entry in a mempak. | |
Functions | |
int | read_mempak_sector (int controller, int sector, uint8_t *sector_data) |
Read a sector from a mempak. | |
int | write_mempak_sector (int controller, int sector, uint8_t *sector_data) |
Write a sector to a mempak. | |
static int | __validate_header (uint8_t *sector) |
Check a mempak header for validity. | |
static uint8_t | __get_toc_checksum (uint8_t *sector) |
Calculate the checksum over a TOC sector. | |
static int | __validate_toc (uint8_t *sector) |
Check a mempak TOC sector for validity. | |
static char | __n64_to_ascii (char c) |
Convert a N64 mempak character to ASCII. | |
static char | __ascii_to_n64 (char c) |
Convert an ASCII character to a N64 mempak character. | |
static int | __validate_region (uint8_t region) |
Check a region read from a mempak entry for validity. | |
static int | __read_note (uint8_t *tnote, entry_structure_t *note) |
Parse a note structure from a TOC. | |
static int | __write_note (entry_structure_t *note, uint8_t *out_note) |
Create a note structure for a mempak TOC. | |
static int | __get_num_pages (uint8_t *sector, int inode) |
Return number of pages a note occupies. | |
static int | __get_free_space (uint8_t *sector) |
Get number of free blocks on a mempak. | |
static int | __get_note_block (uint8_t *sector, int inode, int block) |
Get the inode of the n'th block in a note. | |
static int | __get_valid_toc (int controller) |
Retrieve the sector number of the first valid TOC found. | |
int | validate_mempak (int controller) |
Return whether a mempak is valid. | |
int | get_mempak_entry (int controller, int entry, entry_structure_t *entry_data) |
Read an entry on a mempak. | |
int | get_mempak_free_space (int controller) |
Return the number of free blocks on a mempak. | |
int | format_mempak (int controller) |
Format a mempak. | |
int | read_mempak_entry_data (int controller, entry_structure_t *entry, uint8_t *data) |
Read the data associated with an entry on a mempak. | |
int | write_mempak_entry_data (int controller, entry_structure_t *entry, uint8_t *data) |
Write associated data to a mempak entry. | |
int | delete_mempak_entry (int controller, entry_structure_t *entry) |
Delete a mempak entry and associated data. | |
Inode values | |
#define | BLOCK_EMPTY 0x03 |
This block is empty. | |
#define | BLOCK_LAST 0x01 |
This is the last block in the note. | |
#define | BLOCK_VALID_FIRST 0x05 |
First valid block that can contain user data. | |
#define | BLOCK_VALID_LAST 0x7F |
Last valid block that can contain user data. |
Managed mempak interface.
The mempak system is a subsystem of the Controller Subsystem. Before attempting to read from or write to a mempak, be sure you have initialized the controller system with controller_init and verified that you have a mempak in the correct controller using identify_accessory.
To read and write to the mempak in an organized way compatible with official software, first check that the mempak is valid using validate_mempak. If the mempack is invalid, it will need to be formatted using format_mempak. Once the mempak is considered valid, existing notes can be enumerated using get_mempak_entry. To read the data associated with a note, use read_mempak_entry_data. To write a new note to the mempak, use write_mempak_entry_data. Note that there is no append functionality so if a note is being updated, ensure you have deleted the old note first using delete_mempak_entry. Code should be careful to check how many blocks are free before writing using get_mempak_free_space.
static char __ascii_to_n64 | ( | char | c | ) | [static] |
Convert an ASCII character to a N64 mempak character.
If the character passed in is one that the N64 mempak doesn't support, this function will default to a space.
[in] | c | An ASCII character |
static int __get_free_space | ( | uint8_t * | sector | ) | [static] |
Get number of free blocks on a mempak.
[in] | sector | A valid TOC block to examine |
static int __get_note_block | ( | uint8_t * | sector, |
int | inode, | ||
int | block | ||
) | [static] |
Get the inode of the n'th block in a note.
[in] | sector | A valid TOC sector |
[in] | inode | The starting inode of the note |
[in] | block | The block offset (starting from 0) to retrieve |
-2 | if there were free blocks in the file |
-3 | if the filesystem was invalid |
static int __get_num_pages | ( | uint8_t * | sector, |
int | inode | ||
) | [static] |
Return number of pages a note occupies.
Given a starting inode and a TOC sector, walk the linked list for a note and return the number of pages/blocks/sectors a note occupies.
[in] | sector | A TOC sector |
[in] | inode | A starting inode |
-2 | The file contained free blocks |
-3 | The filesystem was invalid |
static uint8_t __get_toc_checksum | ( | uint8_t * | sector | ) | [static] |
Calculate the checksum over a TOC sector.
[in] | sector | A sector containing a TOC |
static int __get_valid_toc | ( | int | controller | ) | [static] |
Retrieve the sector number of the first valid TOC found.
[in] | controller | The controller (0-3) to inspect for a valid TOC |
-2 | the mempak was not inserted or was bad |
-3 | the mempak was unformatted or the header was invalid |
1 | the first sector has a valid TOC |
2 | the second sector has a valid TOC |
static char __n64_to_ascii | ( | char | c | ) | [static] |
Convert a N64 mempak character to ASCII.
[in] | c | A character read from a mempak entry title |
static int __read_note | ( | uint8_t * | tnote, |
entry_structure_t * | note | ||
) | [static] |
Parse a note structure from a TOC.
Given a note block read from a mempak TOC, parse and return a structure representing the data.
[in] | tnote | 32 bytes read from a mempak TOC |
[out] | note | Parsed note structure |
0 | note was parsed properly |
-1 | parameters were invalid |
-2 | note inode out of bounds |
-3 | note region invalid |
static int __validate_header | ( | uint8_t * | sector | ) | [static] |
Check a mempak header for validity.
[in] | sector | A sector containing a mempak header |
0 | if the header is valid |
-1 | if the header is invalid |
static int __validate_region | ( | uint8_t | region | ) | [static] |
Check a region read from a mempak entry for validity.
[in] | region | A region read from a mempak entry |
0 | if the region is valid |
-1 | if the region is invalid |
static int __validate_toc | ( | uint8_t * | sector | ) | [static] |
Check a mempak TOC sector for validity.
[in] | sector | A sector containing a TOC |
0 | if the TOC is valid |
-1 | if the TOC is invalid |
static int __write_note | ( | entry_structure_t * | note, |
uint8_t * | out_note | ||
) | [static] |
Create a note structure for a mempak TOC.
Given a valid note structure, format it for writing to a mempak TOC
[in] | note | Valid note structure to convert |
[out] | out_note | 32 bytes ready to be written to a mempak TOC |
0 | if the note was converted properly |
-1 | if the parameters were invalid |
int delete_mempak_entry | ( | int | controller, |
entry_structure_t * | entry | ||
) |
Delete a mempak entry and associated data.
Given a valid mempak entry fetched by get_mempak_entry, removes the entry and frees all associated blocks.
[in] | controller | The controller (0-3) to delete the note from |
[in] | entry | The entry structure that is to be deleted from the mempak |
0 | if the entry was deleted successfully |
-1 | if the entry was invalid |
-2 | if the mempak was bad or not present |
int format_mempak | ( | int | controller | ) |
Format a mempak.
Formats a mempak. Should only be done to wipe a mempak or to initialize the filesystem in case of a blank or corrupt mempak.
[in] | controller | The controller (0-3) to format the mempak on |
0 | if the mempak was formatted successfully |
-2 | if the mempak was not present or couldn't be formatted |
int get_mempak_entry | ( | int | controller, |
int | entry, | ||
entry_structure_t * | entry_data | ||
) |
Read an entry on a mempak.
Given an entry index (0-15), return the entry as found on the mempak. If the entry is blank or invalid, the valid flag is cleared.
[in] | controller | The controller (0-3) from which the entry should be read |
[in] | entry | The entry index (0-15) to read |
[out] | entry_data | Structure containing information on the entry |
0 | if the entry was read successfully |
-1 | if the entry is out of bounds or entry_data is null |
-2 | if the mempak is bad or not present |
int get_mempak_free_space | ( | int | controller | ) |
Return the number of free blocks on a mempak.
Note that a block is identical in size to a sector. To calculate the number of bytes free, multiply the return of this function by MEMPAK_BLOCK_SIZE.
[in] | controller | The controller (0-3) to read the free space from |
int read_mempak_entry_data | ( | int | controller, |
entry_structure_t * | entry, | ||
uint8_t * | data | ||
) |
Read the data associated with an entry on a mempak.
Given a valid mempak entry fetched by get_mempak_entry, retrieves the contents of the entry. The calling function must ensure that enough room is available in the passed in buffer for the entire entry. The entry structure itself contains the number of blocks used to store the data which can be multiplied by MEMPAK_BLOCK_SIZE to calculate the size of the buffer needed.
[in] | controller | The controller (0-3) to read the entry data from |
[in] | entry | The entry structure associated with the data to be read. An entry structure can be fetched based on index using get_mempak_entry |
[out] | data | The data associated with an entry |
0 | if the entry was successfully read |
-1 | if input parameters were out of bounds or the entry was corrupted somehow |
-2 | if the mempak was not present or bad |
-3 | if the data couldn't be read |
int read_mempak_sector | ( | int | controller, |
int | sector, | ||
uint8_t * | sector_data | ||
) |
Read a sector from a mempak.
This will read a sector from a mempak. Sectors on mempaks are always 256 bytes in size.
[in] | controller | The controller (0-3) to read a sector from |
[in] | sector | The sector (0-127) to read from |
[out] | sector_data | Buffer to place 256 read bytes of data |
0 | if reading was successful |
-1 | if the sector was out of bounds or sector_data was null |
-2 | if there was an error reading part of a sector |
int validate_mempak | ( | int | controller | ) |
Return whether a mempak is valid.
This function will return whether the mempak in a particular controller is formatted and valid.
[in] | controller | The controller (0-3) to validate |
0 | if the mempak is valid and ready to be used |
-2 | if the mempak is not present or couldn't be read |
-3 | if the mempak is bad or unformatted |
int write_mempak_entry_data | ( | int | controller, |
entry_structure_t * | entry, | ||
uint8_t * | data | ||
) |
Write associated data to a mempak entry.
Given a mempak entry structure with a valid region, name and block count, writes the entry and associated data to the mempak. This function will not overwrite any existing user data. To update an existing entry, use delete_mempak_entry followed by write_mempak_entry_data with the same entry structure.
[in] | controller | The controller (0-3) to write the entry and data to |
[in] | entry | The entry structure containing a region, name and block count |
[in] | data | The associated data to write to to the created entry |
0 | if the entry was created and written successfully |
-1 | if the parameters were invalid or the note has no length |
-2 | if the mempak wasn't present or was bad |
-3 | if there was an error writing to the mempak |
-4 | if there wasn't enough space to store the note |
-5 | if there is no room in the TOC to add a new entry |
int write_mempak_sector | ( | int | controller, |
int | sector, | ||
uint8_t * | sector_data | ||
) |
Write a sector to a mempak.
This will write a sector to a mempak. Sectors on mempaks are always 256 bytes in size.
[in] | controller | The controller (0-3) to write a sector to |
[in] | sector | The sector (0-127) to write to |
[out] | sector_data | Buffer containing 256 bytes of data to write to sector |
0 | if writing was successful |
-1 | if the sector was out of bounds or sector_data was null |
-2 | if there was an error writing part of a sector |