mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2025-05-18 23:39:17 +02:00
189 lines
4.8 KiB
C
189 lines
4.8 KiB
C
/*
|
|
** fygue/flash/cmap - flash cluster map
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <gint/defs/attributes.h>
|
|
|
|
#include "flash.h"
|
|
|
|
//---
|
|
// Internals
|
|
//---
|
|
|
|
/* fygue_flash_cmap_update() - update the cluster redirection map
|
|
*
|
|
* notes
|
|
* Since Casio uses its own methods to handle flash sector and cluster we
|
|
* need to rebuild the translation page between "logical cluster"
|
|
* (lcluster) and "flash cluster" (fcluster).
|
|
*
|
|
* Casio does not erase systematically each sector when they become
|
|
* outdated, instead, they use a `version` mechanism which indicates
|
|
* "when" the cluster has been created to keep the more recent one.
|
|
*
|
|
* return
|
|
* -1 if the provided information is not valid
|
|
* 0 if the provided lcluster exists and has not been updated
|
|
* 1 if the provided lcluster has been created
|
|
* 2 if the provided lcluster exists and has been updated */
|
|
static int fygue_flash_cmap_update(
|
|
struct fygue_flash_cmap *cmap,
|
|
struct fygue_flash_cluster *fcluster
|
|
) {
|
|
struct fygue_flash_cmap_entry *entry;
|
|
int i;
|
|
|
|
if (cmap == NULL || fcluster == NULL)
|
|
return -1;
|
|
if (fcluster->kind != 0x11)
|
|
return -1;
|
|
if (cmap->lcluster_id_max > fcluster->lcluster_id)
|
|
{
|
|
if (
|
|
cmap->lcluster[fcluster->lcluster_id].version != 0xffffffff &&
|
|
cmap->lcluster[fcluster->lcluster_id].version
|
|
< fcluster->version
|
|
) {
|
|
return 1;
|
|
}
|
|
} else {
|
|
cmap->lcluster = reallocarray(
|
|
cmap->lcluster,
|
|
(fcluster->lcluster_id + 1),
|
|
sizeof(struct fygue_flash_cmap_entry)
|
|
);
|
|
for (
|
|
i = cmap->lcluster_id_max ;
|
|
i < fcluster->lcluster_id ;
|
|
i++
|
|
) {
|
|
cmap->lcluster[i].fcluster_id = 0xffff;
|
|
cmap->lcluster[i].fcluster_id_bfile = 0xffff;
|
|
cmap->lcluster[i].fcluster_addr = 0xffffffff;
|
|
cmap->lcluster[i].version = 0xffffffff;
|
|
}
|
|
cmap->lcluster_id_max = fcluster->lcluster_id + 1;
|
|
}
|
|
entry = &(cmap->lcluster[fcluster->lcluster_id]);
|
|
entry->fcluster_id = fcluster->fcluster_id;
|
|
entry->fcluster_id_bfile = fcluster->fcluster_id_bfile;
|
|
entry->fcluster_addr = fcluster->data_addr;
|
|
entry->version = fcluster->version;
|
|
return 0;
|
|
}
|
|
|
|
/* _fygue_flash_cmap_discover(): discover flash information */
|
|
static int _fygue_flash_cmap_discover(
|
|
struct fygue_flash *flash,
|
|
struct fygue_flash_cmap *cmap
|
|
) {
|
|
struct fygue_flash_cluster fcluster;
|
|
int fsector_id;
|
|
int fsector;
|
|
int rc;
|
|
int j;
|
|
|
|
fsector_id = 0;
|
|
for (
|
|
fsector = 0 ;
|
|
fsector < flash->geometry.fsector_count ;
|
|
fsector++
|
|
) {
|
|
if (fsector != 0)
|
|
fsector_id += flash->geometry.fcluster_per_fsector;
|
|
if (fygue_flash_cluster_get(flash, &fcluster, fsector_id) != 0)
|
|
continue;
|
|
if (fcluster.kind != 0x22)
|
|
continue;
|
|
for (j = 1 ; j < (flash->geometry.fcluster_per_fsector - 1) ; j++)
|
|
{
|
|
rc = fygue_flash_cluster_get(flash, &fcluster, fsector_id + j);
|
|
if (rc != 0)
|
|
continue;
|
|
if (fcluster.kind != 0x11)
|
|
continue;
|
|
fygue_flash_cmap_update(cmap, &fcluster);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//---
|
|
// Public
|
|
//---
|
|
|
|
/* fygue_flash_cmap_lsector_get_addr() - get logical sector address */
|
|
int fygue_flash_cmap_lsector_get_addr(
|
|
struct fygue_flash *flash,
|
|
struct fygue_flash_cmap *cmap,
|
|
uintptr_t *sector,
|
|
uint16_t lsector_id
|
|
) {
|
|
uintptr_t fsector_addr;
|
|
uint16_t lcluster_id;
|
|
|
|
if (flash == NULL || sector == NULL || cmap == NULL)
|
|
return -1;
|
|
if (cmap->lcluster == NULL)
|
|
return -1;
|
|
lcluster_id = lsector_id / 8;
|
|
if (
|
|
cmap->lcluster_id_max < lcluster_id ||
|
|
cmap->lcluster[lcluster_id].fcluster_id == 0xffff
|
|
) {
|
|
return -2;
|
|
}
|
|
fsector_addr = cmap->lcluster[lcluster_id].fcluster_addr;
|
|
fsector_addr += (lsector_id % 8) * 512;
|
|
*sector = fsector_addr;
|
|
return 0;
|
|
}
|
|
|
|
/* fygue_flash_cmap_init() - initialize fcluster translation
|
|
*
|
|
* notes:
|
|
* Casio has its own flash handling layer that hooks Fugue primitives to
|
|
* control how/when the hardware will perform IO operations
|
|
* (read,write,erase). This because the Flash used in recent devices use
|
|
* sector of 128ko which implies, when you want to update one byte of
|
|
* memory, you need to:
|
|
* - copy the whole page in RAM
|
|
* - perform the modification
|
|
* - write the new page information
|
|
*
|
|
* todo: docs
|
|
*
|
|
* returns:
|
|
* -1 if the sector 0 is not found
|
|
* 0 success */
|
|
int fygue_flash_cmap_initialize(
|
|
struct fygue_flash *flash,
|
|
struct fygue_flash_cmap *cmap
|
|
) {
|
|
if (flash == NULL || cmap == NULL)
|
|
return -1;
|
|
memset(cmap, 0x00, sizeof(struct fygue_flash_cmap));
|
|
if (_fygue_flash_cmap_discover(flash, cmap) != 0)
|
|
return -1;
|
|
if (cmap->lcluster == NULL)
|
|
return -2;
|
|
if (cmap->lcluster[0].fcluster_id == 0xffff)
|
|
return -3;
|
|
return 0;
|
|
}
|
|
|
|
/* fygue_flash_cmap_sync() - sync the fcluster redirection map */
|
|
int fygue_flash_cmap_sync(
|
|
struct fygue_flash *flash,
|
|
struct fygue_flash_cmap *cmap
|
|
) {
|
|
if (flash == NULL || cmap == NULL)
|
|
return -1;
|
|
for (int i = 0 ; i < cmap->lcluster_id_max ; i++)
|
|
cmap->lcluster[i].version = 0xffffffff;
|
|
if (_fygue_flash_cmap_discover(flash, cmap) != 0)
|
|
return -2;
|
|
return 0;
|
|
}
|