mirror of
https://github.com/wiiu-env/libfat.git
synced 2024-11-22 09:59:18 +01:00
add read ahead cache by Rodries
This commit is contained in:
parent
527a26f299
commit
206ce78022
@ -66,7 +66,7 @@ the disc. Otherwise it will try to mount the partition starting at startSector.
|
|||||||
cacheSize specifies the number of pages to allocate for the cache.
|
cacheSize specifies the number of pages to allocate for the cache.
|
||||||
This will not startup the disc, so you need to call interface->startup(); first.
|
This will not startup the disc, so you need to call interface->startup(); first.
|
||||||
*/
|
*/
|
||||||
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize);
|
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Unmount the partition specified by name.
|
Unmount the partition specified by name.
|
||||||
|
@ -82,7 +82,7 @@ the disc. Otherwise it will try to mount the partition starting at startSector.
|
|||||||
cacheSize specifies the number of pages to allocate for the cache.
|
cacheSize specifies the number of pages to allocate for the cache.
|
||||||
This will not startup the disc, so you need to call interface->startup(); first.
|
This will not startup the disc, so you need to call interface->startup(); first.
|
||||||
*/
|
*/
|
||||||
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize);
|
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Unmount the partition specified by name.
|
Unmount the partition specified by name.
|
||||||
|
@ -66,8 +66,7 @@ the disc. Otherwise it will try to mount the partition starting at startSector.
|
|||||||
cacheSize specifies the number of pages to allocate for the cache.
|
cacheSize specifies the number of pages to allocate for the cache.
|
||||||
This will not startup the disc, so you need to call interface->startup(); first.
|
This will not startup the disc, so you need to call interface->startup(); first.
|
||||||
*/
|
*/
|
||||||
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize);
|
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Unmount the partition specified by name.
|
Unmount the partition specified by name.
|
||||||
If there are open files, it will attempt to synchronise them to disc.
|
If there are open files, it will attempt to synchronise them to disc.
|
||||||
|
@ -71,7 +71,7 @@ the disc. Otherwise it will try to mount the partition starting at startSector.
|
|||||||
cacheSize specifies the number of pages to allocate for the cache.
|
cacheSize specifies the number of pages to allocate for the cache.
|
||||||
This will not startup the disc, so you need to call interface->startup(); first.
|
This will not startup the disc, so you need to call interface->startup(); first.
|
||||||
*/
|
*/
|
||||||
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize);
|
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Unmount the partition specified by name.
|
Unmount the partition specified by name.
|
||||||
|
247
source/cache.c
247
source/cache.c
@ -1,16 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
cache.c
|
cache.c
|
||||||
The cache is not visible to the user. It should be flushed
|
The cache is not visible to the user. It should be flushed
|
||||||
when any file is closed or changes are made to the filesystem.
|
when any file is closed or changes are made to the filesystem.
|
||||||
|
|
||||||
This cache implements a least-used-page replacement policy. This will
|
This cache implements a least-used-page replacement policy. This will
|
||||||
distribute sectors evenly over the pages, so if less than the maximum
|
distribute sectors evenly over the pages, so if less than the maximum
|
||||||
pages are used at once, they should all eventually remain in the cache.
|
pages are used at once, they should all eventually remain in the cache.
|
||||||
This also has the benefit of throwing out old sectors, so as not to keep
|
This also has the benefit of throwing out old sectors, so as not to keep
|
||||||
too many stale pages around.
|
too many stale pages around.
|
||||||
|
|
||||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
are permitted provided that the following conditions are met:
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
@ -42,10 +42,11 @@
|
|||||||
|
|
||||||
#include "mem_allocate.h"
|
#include "mem_allocate.h"
|
||||||
#include "bit_ops.h"
|
#include "bit_ops.h"
|
||||||
|
#include "file_allocation_table.h"
|
||||||
|
|
||||||
#define CACHE_FREE UINT_MAX
|
#define CACHE_FREE UINT_MAX
|
||||||
|
|
||||||
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE* discInterface) {
|
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface) {
|
||||||
CACHE* cache;
|
CACHE* cache;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
CACHE_ENTRY* cacheEntries;
|
CACHE_ENTRY* cacheEntries;
|
||||||
@ -53,7 +54,11 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE*
|
|||||||
if (numberOfPages < 2) {
|
if (numberOfPages < 2) {
|
||||||
numberOfPages = 2;
|
numberOfPages = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sectorsPerPage < 8) {
|
||||||
|
sectorsPerPage = 8;
|
||||||
|
}
|
||||||
|
|
||||||
cache = (CACHE*) _FAT_mem_allocate (sizeof(CACHE));
|
cache = (CACHE*) _FAT_mem_allocate (sizeof(CACHE));
|
||||||
if (cache == NULL) {
|
if (cache == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -61,7 +66,8 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE*
|
|||||||
|
|
||||||
cache->disc = discInterface;
|
cache->disc = discInterface;
|
||||||
cache->numberOfPages = numberOfPages;
|
cache->numberOfPages = numberOfPages;
|
||||||
|
cache->sectorsPerPage = sectorsPerPage;
|
||||||
|
|
||||||
|
|
||||||
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate ( sizeof(CACHE_ENTRY) * numberOfPages);
|
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate ( sizeof(CACHE_ENTRY) * numberOfPages);
|
||||||
if (cacheEntries == NULL) {
|
if (cacheEntries == NULL) {
|
||||||
@ -72,31 +78,33 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE*
|
|||||||
for (i = 0; i < numberOfPages; i++) {
|
for (i = 0; i < numberOfPages; i++) {
|
||||||
cacheEntries[i].sector = CACHE_FREE;
|
cacheEntries[i].sector = CACHE_FREE;
|
||||||
cacheEntries[i].count = 0;
|
cacheEntries[i].count = 0;
|
||||||
|
cacheEntries[i].last_access = 0;
|
||||||
cacheEntries[i].dirty = false;
|
cacheEntries[i].dirty = false;
|
||||||
|
cacheEntries[i].cache = (uint8_t*) _FAT_mem_align ( sectorsPerPage * BYTES_PER_READ );
|
||||||
}
|
}
|
||||||
|
|
||||||
cache->cacheEntries = cacheEntries;
|
cache->cacheEntries = cacheEntries;
|
||||||
|
|
||||||
cache->pages = (uint8_t*) _FAT_mem_allocate ( CACHE_PAGE_SIZE * numberOfPages);
|
|
||||||
if (cache->pages == NULL) {
|
|
||||||
_FAT_mem_free (cache->cacheEntries);
|
|
||||||
_FAT_mem_free (cache);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _FAT_cache_destructor (CACHE* cache) {
|
void _FAT_cache_destructor (CACHE* cache) {
|
||||||
|
unsigned int i;
|
||||||
// Clear out cache before destroying it
|
// Clear out cache before destroying it
|
||||||
_FAT_cache_flush(cache);
|
_FAT_cache_flush(cache);
|
||||||
|
|
||||||
// Free memory in reverse allocation order
|
// Free memory in reverse allocation order
|
||||||
_FAT_mem_free (cache->pages);
|
for (i = 0; i < cache->numberOfPages; i++) {
|
||||||
|
_FAT_mem_free (cache->cacheEntries[i].cache);
|
||||||
|
}
|
||||||
_FAT_mem_free (cache->cacheEntries);
|
_FAT_mem_free (cache->cacheEntries);
|
||||||
_FAT_mem_free (cache);
|
_FAT_mem_free (cache);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
static u32 accessCounter = 0;
|
||||||
|
|
||||||
|
static u32 accessTime(){
|
||||||
|
return accessCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -104,71 +112,147 @@ Retrieve a sector's page from the cache. If it is not found in the cache,
|
|||||||
load it into the cache and return the page it was loaded to.
|
load it into the cache and return the page it was loaded to.
|
||||||
Return CACHE_FREE on error.
|
Return CACHE_FREE on error.
|
||||||
*/
|
*/
|
||||||
static unsigned int _FAT_cache_getSector (CACHE* cache, sec_t sector) {
|
static unsigned int _FAT_cache_getSector (CACHE* cache, sec_t sector, void* buffer) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
unsigned int numberOfPages = cache->numberOfPages;
|
unsigned int numberOfPages = cache->numberOfPages;
|
||||||
|
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||||
|
|
||||||
unsigned int leastUsed = 0;
|
unsigned int oldUsed = 0;
|
||||||
unsigned int lowestCount = UINT_MAX;
|
unsigned int oldAccess = cacheEntries[0].last_access;
|
||||||
|
|
||||||
for (i = 0; (i < numberOfPages) && (cacheEntries[i].sector != sector); i++) {
|
for (i = 0; i < numberOfPages ; i++) {
|
||||||
// While searching for the desired sector, also search for the leased used page
|
if ( sector>=cacheEntries[i].sector && sector < cacheEntries[i].sector+cacheEntries[i].count) {
|
||||||
if ( (cacheEntries[i].sector == CACHE_FREE) || (cacheEntries[i].count < lowestCount) ) {
|
cacheEntries[i].last_access = accessTime();
|
||||||
leastUsed = i;
|
memcpy(buffer, cacheEntries[i].cache + ((sector - cacheEntries[i].sector)*BYTES_PER_READ), BYTES_PER_READ);
|
||||||
lowestCount = cacheEntries[i].count;
|
return true;
|
||||||
|
}
|
||||||
|
// While searching for the desired sector, also search for the least recently used page
|
||||||
|
if ( (cacheEntries[i].sector == CACHE_FREE) || (cacheEntries[i].last_access < oldAccess) ) {
|
||||||
|
oldUsed = i;
|
||||||
|
oldAccess = cacheEntries[i].last_access;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it found the sector in the cache, return it
|
|
||||||
if ((i < numberOfPages) && (cacheEntries[i].sector == sector)) {
|
|
||||||
// Increment usage counter
|
|
||||||
cacheEntries[i].count += 1;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it didn't, replace the least used cache page with the desired sector
|
// If it didn't, replace the least used cache page with the desired sector
|
||||||
if ((cacheEntries[leastUsed].sector != CACHE_FREE) && (cacheEntries[leastUsed].dirty == true)) {
|
if ((cacheEntries[oldUsed].sector != CACHE_FREE) && (cacheEntries[oldUsed].dirty == true)) {
|
||||||
// Write the page back to disc if it has been written to
|
// Write the page back to disc if it has been written to
|
||||||
if (!_FAT_disc_writeSectors (cache->disc, cacheEntries[leastUsed].sector, 1, cache->pages + CACHE_PAGE_SIZE * leastUsed)) {
|
if (!_FAT_disc_writeSectors (cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache)) {
|
||||||
return CACHE_FREE;
|
return false;
|
||||||
}
|
}
|
||||||
cacheEntries[leastUsed].dirty = false;
|
cacheEntries[oldUsed].dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the new sector into the cache
|
// Load the new sector into the cache
|
||||||
if (!_FAT_disc_readSectors (cache->disc, sector, 1, cache->pages + CACHE_PAGE_SIZE * leastUsed)) {
|
if (!_FAT_disc_readSectors (cache->disc, sector, sectorsPerPage, cacheEntries[oldUsed].cache)) {
|
||||||
return CACHE_FREE;
|
return false;
|
||||||
}
|
}
|
||||||
cacheEntries[leastUsed].sector = sector;
|
cacheEntries[oldUsed].sector = sector;
|
||||||
|
cacheEntries[oldUsed].count = sectorsPerPage;
|
||||||
// Increment the usage count, don't reset it
|
// Increment the usage count, don't reset it
|
||||||
// This creates a paging policy of least used PAGE, not sector
|
// This creates a paging policy of least recently used PAGE, not sector
|
||||||
cacheEntries[leastUsed].count += 1;
|
cacheEntries[oldUsed].last_access = accessTime();
|
||||||
return leastUsed;
|
memcpy(buffer, cacheEntries[oldUsed].cache, BYTES_PER_READ);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _FAT_cache_getSectors (CACHE* cache, sec_t sector, sec_t numSectors, void* buffer) {
|
||||||
|
unsigned int i;
|
||||||
|
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
|
unsigned int numberOfPages = cache->numberOfPages;
|
||||||
|
sec_t sec;
|
||||||
|
sec_t secs_to_read;
|
||||||
|
|
||||||
|
unsigned int oldUsed = 0;
|
||||||
|
unsigned int oldAccess = cacheEntries[0].last_access;
|
||||||
|
accessCounter++;
|
||||||
|
|
||||||
|
while(numSectors>0)
|
||||||
|
{
|
||||||
|
i=0;
|
||||||
|
while (i < numberOfPages ) {
|
||||||
|
if ( sector>=cacheEntries[i].sector && sector < cacheEntries[i].sector+cacheEntries[i].count) {
|
||||||
|
sec=sector-cacheEntries[i].sector;
|
||||||
|
secs_to_read=cacheEntries[i].count-sec;
|
||||||
|
if(secs_to_read>numSectors)secs_to_read=numSectors;
|
||||||
|
memcpy(buffer,cacheEntries[i].cache + (sec*BYTES_PER_READ), secs_to_read*BYTES_PER_READ);
|
||||||
|
cacheEntries[i].last_access = accessTime();
|
||||||
|
numSectors=numSectors-secs_to_read;
|
||||||
|
if(numSectors==0) return true;
|
||||||
|
buffer+=secs_to_read*BYTES_PER_READ;
|
||||||
|
sector+=secs_to_read;
|
||||||
|
i=-1; // recheck all pages again
|
||||||
|
oldUsed = 0;
|
||||||
|
oldAccess = cacheEntries[0].last_access;
|
||||||
|
|
||||||
|
}
|
||||||
|
else // While searching for the desired sector, also search for the least recently used page
|
||||||
|
if ( (cacheEntries[i].sector == CACHE_FREE) || (cacheEntries[i].last_access < oldAccess) ) {
|
||||||
|
oldUsed = i;
|
||||||
|
oldAccess = cacheEntries[i].last_access;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
// If it didn't, replace the least recently used cache page with the desired sector
|
||||||
|
if ((cacheEntries[oldUsed].sector != CACHE_FREE) && (cacheEntries[oldUsed].dirty == true)) {
|
||||||
|
// Write the page back to disc if it has been written to
|
||||||
|
if (!_FAT_disc_writeSectors (cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cacheEntries[oldUsed].dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cacheEntries[oldUsed].count = cache->sectorsPerPage;
|
||||||
|
if (!_FAT_disc_readSectors (cache->disc, sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheEntries[oldUsed].sector = sector;
|
||||||
|
// Increment the usage count, don't reset it
|
||||||
|
// This creates a paging policy of least used PAGE, not sector
|
||||||
|
cacheEntries[oldUsed].last_access = accessTime();
|
||||||
|
|
||||||
|
sec=0;
|
||||||
|
secs_to_read=cacheEntries[oldUsed].count-sec;
|
||||||
|
if(secs_to_read>numSectors)secs_to_read=numSectors;
|
||||||
|
memcpy(buffer,cacheEntries[oldUsed].cache + (sec*BYTES_PER_READ), secs_to_read*BYTES_PER_READ);
|
||||||
|
numSectors=numSectors-secs_to_read;
|
||||||
|
if(numSectors==0) return true;
|
||||||
|
buffer+=secs_to_read*BYTES_PER_READ;
|
||||||
|
|
||||||
|
sector+=secs_to_read;
|
||||||
|
oldUsed = 0;
|
||||||
|
oldAccess = cacheEntries[0].last_access;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reads some data from a cache page, determined by the sector number
|
Reads some data from a cache page, determined by the sector number
|
||||||
*/
|
*/
|
||||||
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size) {
|
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size) {
|
||||||
unsigned int page;
|
void* sec;
|
||||||
|
|
||||||
if (offset + size > BYTES_PER_READ) {
|
if (offset + size > BYTES_PER_READ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
sec = (void*) _FAT_mem_align ( BYTES_PER_READ );
|
||||||
page = _FAT_cache_getSector (cache, sector);
|
if(sec == NULL) return false;
|
||||||
if (page == CACHE_FREE) {
|
if(! _FAT_cache_getSector(cache, sector, sec) ) {
|
||||||
|
_FAT_mem_free(sec);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memcpy (buffer, cache->pages + (CACHE_PAGE_SIZE * page) + offset, size);
|
memcpy(buffer, sec + offset, size);
|
||||||
|
_FAT_mem_free(sec);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||||
uint8_t buf[4];
|
uint8_t buf[4];
|
||||||
if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||||
|
|
||||||
switch(num_bytes) {
|
switch(num_bytes) {
|
||||||
case 1: *value = buf[0]; break;
|
case 1: *value = buf[0]; break;
|
||||||
case 2: *value = u8array_to_u16(buf,0); break;
|
case 2: *value = u8array_to_u16(buf,0); break;
|
||||||
@ -178,25 +262,38 @@ bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sect
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
Writes some data to a cache page, making sure it is loaded into memory first.
|
||||||
*/
|
*/
|
||||||
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size) {
|
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size) {
|
||||||
unsigned int page;
|
unsigned int i;
|
||||||
|
void* sec;
|
||||||
|
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
|
unsigned int numberOfPages = cache->numberOfPages;
|
||||||
|
|
||||||
if (offset + size > BYTES_PER_READ) {
|
if (offset + size > BYTES_PER_READ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
page = _FAT_cache_getSector (cache, sector);
|
//To be sure sector is in cache
|
||||||
if (page == CACHE_FREE) {
|
sec = (void*) _FAT_mem_align ( BYTES_PER_READ );
|
||||||
|
if(sec == NULL) return false;
|
||||||
|
if(! _FAT_cache_getSector(cache, sector, sec) ) {
|
||||||
|
_FAT_mem_free(sec);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
_FAT_mem_free(sec);
|
||||||
memcpy (cache->pages + (CACHE_PAGE_SIZE * page) + offset, buffer, size);
|
|
||||||
cache->cacheEntries[page].dirty = true;
|
|
||||||
|
|
||||||
return true;
|
//Find where sector is and write
|
||||||
|
for (i = 0; i < numberOfPages ; i++) {
|
||||||
|
if ( sector>=cacheEntries[i].sector && sector < cacheEntries[i].sector+cacheEntries[i].count) {
|
||||||
|
cacheEntries[i].last_access = accessTime();
|
||||||
|
memcpy (cacheEntries[i].cache + ((sector-cacheEntries[i].sector)*BYTES_PER_READ) + offset, buffer, size);
|
||||||
|
cache->cacheEntries[i].dirty = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size) {
|
||||||
@ -212,43 +309,54 @@ bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_
|
|||||||
return _FAT_cache_writePartialSector(cache, buf, sector, offset, size);
|
return _FAT_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Writes some data to a cache page, zeroing out the page first
|
Writes some data to a cache page, zeroing out the page first
|
||||||
*/
|
*/
|
||||||
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size) {
|
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size) {
|
||||||
unsigned int page;
|
unsigned int i;
|
||||||
|
void* sec;
|
||||||
|
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||||
|
unsigned int numberOfPages = cache->numberOfPages;
|
||||||
|
|
||||||
if (offset + size > BYTES_PER_READ) {
|
if (offset + size > BYTES_PER_READ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
page = _FAT_cache_getSector (cache, sector);
|
//To be sure sector is in cache
|
||||||
if (page == CACHE_FREE) {
|
sec = (void*) _FAT_mem_align ( BYTES_PER_READ );
|
||||||
|
if(sec == NULL) return false;
|
||||||
|
if(! _FAT_cache_getSector(cache, sector, sec) ) {
|
||||||
|
_FAT_mem_free(sec);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
_FAT_mem_free(sec);
|
||||||
memset (cache->pages + (CACHE_PAGE_SIZE * page), 0, CACHE_PAGE_SIZE);
|
|
||||||
memcpy (cache->pages + (CACHE_PAGE_SIZE * page) + offset, buffer, size);
|
|
||||||
cache->cacheEntries[page].dirty = true;
|
|
||||||
|
|
||||||
return true;
|
//Find where sector is and write
|
||||||
|
for (i = 0; i < numberOfPages ; i++) {
|
||||||
|
if ( sector>=cacheEntries[i].sector && sector < cacheEntries[i].sector+cacheEntries[i].count) {
|
||||||
|
cacheEntries[i].last_access = accessTime();
|
||||||
|
memset (cacheEntries[i].cache + ((sector-cacheEntries[i].sector)*BYTES_PER_READ), 0, BYTES_PER_READ);
|
||||||
|
memcpy (cacheEntries[i].cache + ((sector-cacheEntries[i].sector)*BYTES_PER_READ) + offset, buffer, size);
|
||||||
|
cache->cacheEntries[i].dirty = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||||
Also resets all pages' page count to 0.
|
|
||||||
*/
|
*/
|
||||||
bool _FAT_cache_flush (CACHE* cache) {
|
bool _FAT_cache_flush (CACHE* cache) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for (i = 0; i < cache->numberOfPages; i++) {
|
||||||
if (cache->cacheEntries[i].dirty) {
|
if (cache->cacheEntries[i].dirty) {
|
||||||
if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, 1, cache->pages + CACHE_PAGE_SIZE * i)) {
|
if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cache->cacheEntries[i].count = 0;
|
|
||||||
cache->cacheEntries[i].dirty = false;
|
cache->cacheEntries[i].dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,10 +365,11 @@ bool _FAT_cache_flush (CACHE* cache) {
|
|||||||
|
|
||||||
void _FAT_cache_invalidate (CACHE* cache) {
|
void _FAT_cache_invalidate (CACHE* cache) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
_FAT_cache_flush(cache);
|
||||||
for (i = 0; i < cache->numberOfPages; i++) {
|
for (i = 0; i < cache->numberOfPages; i++) {
|
||||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||||
|
cache->cacheEntries[i].last_access = 0;
|
||||||
cache->cacheEntries[i].count = 0;
|
cache->cacheEntries[i].count = 0;
|
||||||
cache->cacheEntries[i].dirty = false;
|
cache->cacheEntries[i].dirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,22 +39,24 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "disc.h"
|
#include "disc.h"
|
||||||
|
|
||||||
#define CACHE_PAGE_SIZE BYTES_PER_READ
|
#define PAGE_SECTORS 64
|
||||||
|
#define CACHE_PAGE_SIZE (BYTES_PER_READ * PAGE_SECTORS)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sec_t sector;
|
sec_t sector;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
unsigned int last_access;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
|
uint8_t* cache;
|
||||||
} CACHE_ENTRY;
|
} CACHE_ENTRY;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const DISC_INTERFACE* disc;
|
const DISC_INTERFACE* disc;
|
||||||
unsigned int numberOfPages;
|
unsigned int numberOfPages;
|
||||||
|
unsigned int sectorsPerPage;
|
||||||
CACHE_ENTRY* cacheEntries;
|
CACHE_ENTRY* cacheEntries;
|
||||||
uint8_t* pages;
|
|
||||||
} CACHE;
|
} CACHE;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read data from a sector in the cache
|
Read data from a sector in the cache
|
||||||
If the sector is not in the cache, it will be swapped in
|
If the sector is not in the cache, it will be swapped in
|
||||||
@ -88,6 +90,11 @@ Precondition: offset + size <= BYTES_PER_READ
|
|||||||
*/
|
*/
|
||||||
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read several sectors from the cache
|
||||||
|
*/
|
||||||
|
bool _FAT_cache_getSectors (CACHE* cache, sec_t sector, sec_t numSectors, void* buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read a full sector from the cache
|
Read a full sector from the cache
|
||||||
*/
|
*/
|
||||||
@ -112,7 +119,7 @@ Clear out the contents of the cache without writing any dirty sectors first
|
|||||||
*/
|
*/
|
||||||
void _FAT_cache_invalidate (CACHE* cache);
|
void _FAT_cache_invalidate (CACHE* cache);
|
||||||
|
|
||||||
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE* discInterface);
|
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface);
|
||||||
|
|
||||||
void _FAT_cache_destructor (CACHE* cache);
|
void _FAT_cache_destructor (CACHE* cache);
|
||||||
|
|
||||||
|
@ -57,19 +57,23 @@
|
|||||||
|
|
||||||
// Platform specific options
|
// Platform specific options
|
||||||
#if defined (__wii__)
|
#if defined (__wii__)
|
||||||
#define DEFAULT_CACHE_PAGES 8
|
#define DEFAULT_CACHE_PAGES 4
|
||||||
|
#define DEFAULT_SECTORS_PAGE 64
|
||||||
#define USE_LWP_LOCK
|
#define USE_LWP_LOCK
|
||||||
#define USE_RTC_TIME
|
#define USE_RTC_TIME
|
||||||
#elif defined (__gamecube__)
|
#elif defined (__gamecube__)
|
||||||
#define DEFAULT_CACHE_PAGES 8
|
#define DEFAULT_CACHE_PAGES 4
|
||||||
|
#define DEFAULT_SECTORS_PAGE 64
|
||||||
#define USE_LWP_LOCK
|
#define USE_LWP_LOCK
|
||||||
#define USE_RTC_TIME
|
#define USE_RTC_TIME
|
||||||
#elif defined (NDS)
|
#elif defined (NDS)
|
||||||
#define DEFAULT_CACHE_PAGES 8
|
#define DEFAULT_CACHE_PAGES 4
|
||||||
|
#define DEFAULT_SECTORS_PAGE 8
|
||||||
#define USE_RTC_TIME
|
#define USE_RTC_TIME
|
||||||
#define LIMIT_SECTORS 128
|
#define LIMIT_SECTORS 128
|
||||||
#elif defined (GBA)
|
#elif defined (GBA)
|
||||||
#define DEFAULT_CACHE_PAGES 2
|
#define DEFAULT_CACHE_PAGES 2
|
||||||
|
#define DEFAULT_SECTORS_PAGE 8
|
||||||
#define LIMIT_SECTORS 128
|
#define LIMIT_SECTORS 128
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "file_allocation_table.h"
|
#include "file_allocation_table.h"
|
||||||
@ -244,6 +245,10 @@ int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags
|
|||||||
|
|
||||||
_FAT_unlock(&partition->lock);
|
_FAT_unlock(&partition->lock);
|
||||||
|
|
||||||
|
/*FILE *fp;
|
||||||
|
fp=__sfp(r);
|
||||||
|
fp->_file = (int) file;
|
||||||
|
setvbuf(fp,NULL,_IONBF,0);*/
|
||||||
return (int) file;
|
return (int) file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,6 +340,33 @@ int _FAT_close_r (struct _reent *r, int fd) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sec_t _FAT_Num_Sectors_To_Cache(CACHE* cache, FILE_POSITION position,PARTITION* partition) {
|
||||||
|
uint32_t limit;
|
||||||
|
uint32_t ra_start, ra_end, ra_sectors;
|
||||||
|
|
||||||
|
|
||||||
|
limit = cache->sectorsPerPage;
|
||||||
|
|
||||||
|
ra_start = position.cluster;
|
||||||
|
ra_sectors = - position.sector;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
ra_end = ra_start;
|
||||||
|
ra_start = _FAT_fat_nextCluster(partition, ra_end);
|
||||||
|
|
||||||
|
if (ra_start != ra_end + 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ra_sectors += partition->sectorsPerCluster;
|
||||||
|
|
||||||
|
if (ra_sectors >= limit)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ra_sectors > limit) ra_sectors = limit;
|
||||||
|
|
||||||
|
return ra_sectors;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
|
ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
|
||||||
FILE_STRUCT* file = (FILE_STRUCT*) fd;
|
FILE_STRUCT* file = (FILE_STRUCT*) fd;
|
||||||
@ -407,7 +439,7 @@ ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((tempVar > 0) && flagNoError) {
|
if ((tempVar > 0) && flagNoError) {
|
||||||
if (! _FAT_disc_readSectors (partition->disc, _FAT_fat_clusterToSector (partition, position.cluster) + position.sector,
|
if (! _FAT_cache_getSectors (cache, _FAT_fat_clusterToSector (partition, position.cluster) + position.sector,
|
||||||
tempVar, ptr))
|
tempVar, ptr))
|
||||||
{
|
{
|
||||||
flagNoError = false;
|
flagNoError = false;
|
||||||
@ -450,7 +482,7 @@ ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
|
|||||||
#endif
|
#endif
|
||||||
(chunkSize + partition->bytesPerCluster <= remain));
|
(chunkSize + partition->bytesPerCluster <= remain));
|
||||||
|
|
||||||
if (!_FAT_disc_readSectors (partition->disc, _FAT_fat_clusterToSector (partition, position.cluster),
|
if (!_FAT_cache_getSectors (cache, _FAT_fat_clusterToSector (partition, position.cluster),
|
||||||
chunkSize / BYTES_PER_READ, ptr))
|
chunkSize / BYTES_PER_READ, ptr))
|
||||||
{
|
{
|
||||||
flagNoError = false;
|
flagNoError = false;
|
||||||
@ -476,7 +508,7 @@ ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
|
|||||||
// Read remaining sectors
|
// Read remaining sectors
|
||||||
tempVar = remain / BYTES_PER_READ; // Number of sectors left
|
tempVar = remain / BYTES_PER_READ; // Number of sectors left
|
||||||
if ((tempVar > 0) && flagNoError) {
|
if ((tempVar > 0) && flagNoError) {
|
||||||
if (!_FAT_disc_readSectors (partition->disc, _FAT_fat_clusterToSector (partition, position.cluster),
|
if (!_FAT_cache_getSectors (cache, _FAT_fat_clusterToSector (partition, position.cluster),
|
||||||
tempVar, ptr))
|
tempVar, ptr))
|
||||||
{
|
{
|
||||||
flagNoError = false;
|
flagNoError = false;
|
||||||
|
@ -64,8 +64,7 @@ static const devoptab_t dotab_fat = {
|
|||||||
NULL /* Device data */
|
NULL /* Device data */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage) {
|
||||||
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize) {
|
|
||||||
PARTITION* partition;
|
PARTITION* partition;
|
||||||
devoptab_t* devops;
|
devoptab_t* devops;
|
||||||
char* nameCopy;
|
char* nameCopy;
|
||||||
@ -78,7 +77,7 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
|
|||||||
nameCopy = (char*)(devops+1);
|
nameCopy = (char*)(devops+1);
|
||||||
|
|
||||||
// Initialize the file system
|
// Initialize the file system
|
||||||
partition = _FAT_partition_constructor (interface, cacheSize, startSector);
|
partition = _FAT_partition_constructor (interface, cacheSize, SectorsPerPage, startSector);
|
||||||
if (!partition) {
|
if (!partition) {
|
||||||
_FAT_mem_free (devops);
|
_FAT_mem_free (devops);
|
||||||
return false;
|
return false;
|
||||||
@ -96,7 +95,7 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool fatMountSimple (const char* name, const DISC_INTERFACE* interface) {
|
bool fatMountSimple (const char* name, const DISC_INTERFACE* interface) {
|
||||||
return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES);
|
return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fatUnmount (const char* name) {
|
void fatUnmount (const char* name) {
|
||||||
@ -132,7 +131,7 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
|||||||
i++)
|
i++)
|
||||||
{
|
{
|
||||||
disc = _FAT_disc_interfaces[i].getInterface();
|
disc = _FAT_disc_interfaces[i].getInterface();
|
||||||
if (disc->startup() && fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize)) {
|
if (disc->startup() && fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE)) {
|
||||||
// The first device to successfully mount is set as the default
|
// The first device to successfully mount is set as the default
|
||||||
if (defaultDevice < 0) {
|
if (defaultDevice < 0) {
|
||||||
defaultDevice = i;
|
defaultDevice = i;
|
||||||
|
@ -37,6 +37,14 @@ static inline void* _FAT_mem_allocate (size_t size) {
|
|||||||
return malloc (size);
|
return malloc (size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void* _FAT_mem_align (size_t size) {
|
||||||
|
#ifdef __wii__
|
||||||
|
return memalign (32, size);
|
||||||
|
#else
|
||||||
|
return malloc (size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline void _FAT_mem_free (void* mem) {
|
static inline void _FAT_mem_free (void* mem) {
|
||||||
free (mem);
|
free (mem);
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ enum BPB {
|
|||||||
static const char FAT_SIG[3] = {'F', 'A', 'T'};
|
static const char FAT_SIG[3] = {'F', 'A', 'T'};
|
||||||
|
|
||||||
|
|
||||||
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, sec_t startSector) {
|
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector) {
|
||||||
PARTITION* partition;
|
PARTITION* partition;
|
||||||
int i;
|
int i;
|
||||||
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
uint8_t sectorBuffer[BYTES_PER_READ] = {0};
|
||||||
@ -220,7 +220,7 @@ PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cach
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a cache to use
|
// Create a cache to use
|
||||||
partition->cache = _FAT_cache_constructor (cacheSize, partition->disc);
|
partition->cache = _FAT_cache_constructor (cacheSize, sectorsPerPage, partition->disc);
|
||||||
|
|
||||||
// Set current directory to the root
|
// Set current directory to the root
|
||||||
partition->cwdCluster = partition->rootDirCluster;
|
partition->cwdCluster = partition->rootDirCluster;
|
||||||
|
@ -72,7 +72,7 @@ typedef struct {
|
|||||||
/*
|
/*
|
||||||
Mount the supplied device and return a pointer to the struct necessary to use it
|
Mount the supplied device and return a pointer to the struct necessary to use it
|
||||||
*/
|
*/
|
||||||
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, sec_t startSector);
|
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t SectorsPerPage, sec_t startSector);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Dismount the device and free all structures used.
|
Dismount the device and free all structures used.
|
||||||
|
Loading…
Reference in New Issue
Block a user