mirror of
https://github.com/wiiu-env/libfat.git
synced 2024-11-22 01:49:17 +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.
|
||||
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.
|
||||
|
@ -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.
|
||||
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.
|
||||
|
@ -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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
|
247
source/cache.c
247
source/cache.c
@ -1,16 +1,16 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
This cache implements a least-used-page replacement policy. This will
|
||||
distribute sectors evenly over the pages, so if less than the maximum
|
||||
|
||||
This cache implements a least-used-page replacement policy. This will
|
||||
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.
|
||||
This also has the benefit of throwing out old sectors, so as not to keep
|
||||
too many stale pages around.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
@ -42,10 +42,11 @@
|
||||
|
||||
#include "mem_allocate.h"
|
||||
#include "bit_ops.h"
|
||||
#include "file_allocation_table.h"
|
||||
|
||||
#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;
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
@ -53,7 +54,11 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE*
|
||||
if (numberOfPages < 2) {
|
||||
numberOfPages = 2;
|
||||
}
|
||||
|
||||
|
||||
if (sectorsPerPage < 8) {
|
||||
sectorsPerPage = 8;
|
||||
}
|
||||
|
||||
cache = (CACHE*) _FAT_mem_allocate (sizeof(CACHE));
|
||||
if (cache == NULL) {
|
||||
return NULL;
|
||||
@ -61,7 +66,8 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE*
|
||||
|
||||
cache->disc = discInterface;
|
||||
cache->numberOfPages = numberOfPages;
|
||||
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
|
||||
|
||||
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate ( sizeof(CACHE_ENTRY) * numberOfPages);
|
||||
if (cacheEntries == NULL) {
|
||||
@ -72,31 +78,33 @@ CACHE* _FAT_cache_constructor (unsigned int numberOfPages, const DISC_INTERFACE*
|
||||
for (i = 0; i < numberOfPages; i++) {
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
cacheEntries[i].dirty = false;
|
||||
cacheEntries[i].cache = (uint8_t*) _FAT_mem_align ( sectorsPerPage * BYTES_PER_READ );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void _FAT_cache_destructor (CACHE* cache) {
|
||||
unsigned int i;
|
||||
// Clear out cache before destroying it
|
||||
_FAT_cache_flush(cache);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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.
|
||||
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;
|
||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||
|
||||
unsigned int leastUsed = 0;
|
||||
unsigned int lowestCount = UINT_MAX;
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = cacheEntries[0].last_access;
|
||||
|
||||
for (i = 0; (i < numberOfPages) && (cacheEntries[i].sector != sector); i++) {
|
||||
// While searching for the desired sector, also search for the leased used page
|
||||
if ( (cacheEntries[i].sector == CACHE_FREE) || (cacheEntries[i].count < lowestCount) ) {
|
||||
leastUsed = i;
|
||||
lowestCount = cacheEntries[i].count;
|
||||
for (i = 0; i < numberOfPages ; i++) {
|
||||
if ( sector>=cacheEntries[i].sector && sector < cacheEntries[i].sector+cacheEntries[i].count) {
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
memcpy(buffer, cacheEntries[i].cache + ((sector - cacheEntries[i].sector)*BYTES_PER_READ), BYTES_PER_READ);
|
||||
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 ((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
|
||||
if (!_FAT_disc_writeSectors (cache->disc, cacheEntries[leastUsed].sector, 1, cache->pages + CACHE_PAGE_SIZE * leastUsed)) {
|
||||
return CACHE_FREE;
|
||||
if (!_FAT_disc_writeSectors (cache->disc, cacheEntries[oldUsed].sector, cacheEntries[oldUsed].count, cacheEntries[oldUsed].cache)) {
|
||||
return false;
|
||||
}
|
||||
cacheEntries[leastUsed].dirty = false;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
|
||||
// Load the new sector into the cache
|
||||
if (!_FAT_disc_readSectors (cache->disc, sector, 1, cache->pages + CACHE_PAGE_SIZE * leastUsed)) {
|
||||
return CACHE_FREE;
|
||||
if (!_FAT_disc_readSectors (cache->disc, sector, sectorsPerPage, cacheEntries[oldUsed].cache)) {
|
||||
return false;
|
||||
}
|
||||
cacheEntries[leastUsed].sector = sector;
|
||||
cacheEntries[oldUsed].sector = sector;
|
||||
cacheEntries[oldUsed].count = sectorsPerPage;
|
||||
// Increment the usage count, don't reset it
|
||||
// This creates a paging policy of least used PAGE, not sector
|
||||
cacheEntries[leastUsed].count += 1;
|
||||
return leastUsed;
|
||||
// This creates a paging policy of least recently used PAGE, not sector
|
||||
cacheEntries[oldUsed].last_access = accessTime();
|
||||
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
|
||||
*/
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
page = _FAT_cache_getSector (cache, sector);
|
||||
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;
|
||||
}
|
||||
memcpy (buffer, cache->pages + (CACHE_PAGE_SIZE * page) + offset, size);
|
||||
memcpy(buffer, sec + offset, size);
|
||||
_FAT_mem_free(sec);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes) {
|
||||
uint8_t buf[4];
|
||||
if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||
|
||||
|
||||
switch(num_bytes) {
|
||||
case 1: *value = 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;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
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) {
|
||||
unsigned int page;
|
||||
unsigned int i;
|
||||
void* sec;
|
||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
|
||||
if (offset + size > BYTES_PER_READ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
page = _FAT_cache_getSector (cache, sector);
|
||||
if (page == CACHE_FREE) {
|
||||
//To be sure sector is in cache
|
||||
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;
|
||||
}
|
||||
|
||||
memcpy (cache->pages + (CACHE_PAGE_SIZE * page) + offset, buffer, size);
|
||||
cache->cacheEntries[page].dirty = true;
|
||||
_FAT_mem_free(sec);
|
||||
|
||||
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) {
|
||||
@ -212,43 +309,54 @@ bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_
|
||||
return _FAT_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
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) {
|
||||
unsigned int page;
|
||||
unsigned int i;
|
||||
void* sec;
|
||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
|
||||
if (offset + size > BYTES_PER_READ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
page = _FAT_cache_getSector (cache, sector);
|
||||
if (page == CACHE_FREE) {
|
||||
//To be sure sector is in cache
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
_FAT_mem_free(sec);
|
||||
|
||||
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.
|
||||
Also resets all pages' page count to 0.
|
||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||
*/
|
||||
bool _FAT_cache_flush (CACHE* cache) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
cache->cacheEntries[i].count = 0;
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
|
||||
@ -257,10 +365,11 @@ bool _FAT_cache_flush (CACHE* cache) {
|
||||
|
||||
void _FAT_cache_invalidate (CACHE* cache) {
|
||||
unsigned int i;
|
||||
_FAT_cache_flush(cache);
|
||||
for (i = 0; i < cache->numberOfPages; i++) {
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,22 +39,24 @@
|
||||
#include "common.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 {
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
bool dirty;
|
||||
uint8_t* cache;
|
||||
} CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
const DISC_INTERFACE* disc;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
uint8_t* pages;
|
||||
} CACHE;
|
||||
|
||||
|
||||
/*
|
||||
Read data from a sector in the cache
|
||||
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);
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
@ -112,7 +119,7 @@ Clear out the contents of the cache without writing any dirty sectors first
|
||||
*/
|
||||
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);
|
||||
|
||||
|
@ -57,19 +57,23 @@
|
||||
|
||||
// Platform specific options
|
||||
#if defined (__wii__)
|
||||
#define DEFAULT_CACHE_PAGES 8
|
||||
#define DEFAULT_CACHE_PAGES 4
|
||||
#define DEFAULT_SECTORS_PAGE 64
|
||||
#define USE_LWP_LOCK
|
||||
#define USE_RTC_TIME
|
||||
#elif defined (__gamecube__)
|
||||
#define DEFAULT_CACHE_PAGES 8
|
||||
#define DEFAULT_CACHE_PAGES 4
|
||||
#define DEFAULT_SECTORS_PAGE 64
|
||||
#define USE_LWP_LOCK
|
||||
#define USE_RTC_TIME
|
||||
#elif defined (NDS)
|
||||
#define DEFAULT_CACHE_PAGES 8
|
||||
#define DEFAULT_CACHE_PAGES 4
|
||||
#define DEFAULT_SECTORS_PAGE 8
|
||||
#define USE_RTC_TIME
|
||||
#define LIMIT_SECTORS 128
|
||||
#elif defined (GBA)
|
||||
#define DEFAULT_CACHE_PAGES 2
|
||||
#define DEFAULT_SECTORS_PAGE 8
|
||||
#define LIMIT_SECTORS 128
|
||||
#endif
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cache.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);
|
||||
|
||||
/*FILE *fp;
|
||||
fp=__sfp(r);
|
||||
fp->_file = (int) file;
|
||||
setvbuf(fp,NULL,_IONBF,0);*/
|
||||
return (int) file;
|
||||
}
|
||||
|
||||
@ -335,6 +340,33 @@ int _FAT_close_r (struct _reent *r, int fd) {
|
||||
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) {
|
||||
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 (! _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))
|
||||
{
|
||||
flagNoError = false;
|
||||
@ -450,7 +482,7 @@ ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
|
||||
#endif
|
||||
(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))
|
||||
{
|
||||
flagNoError = false;
|
||||
@ -476,7 +508,7 @@ ssize_t _FAT_read_r (struct _reent *r, int fd, char *ptr, size_t len) {
|
||||
// Read remaining sectors
|
||||
tempVar = remain / BYTES_PER_READ; // Number of sectors left
|
||||
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))
|
||||
{
|
||||
flagNoError = false;
|
||||
|
@ -64,8 +64,7 @@ static const devoptab_t dotab_fat = {
|
||||
NULL /* Device data */
|
||||
};
|
||||
|
||||
|
||||
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize) {
|
||||
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage) {
|
||||
PARTITION* partition;
|
||||
devoptab_t* devops;
|
||||
char* nameCopy;
|
||||
@ -78,7 +77,7 @@ bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSec
|
||||
nameCopy = (char*)(devops+1);
|
||||
|
||||
// Initialize the file system
|
||||
partition = _FAT_partition_constructor (interface, cacheSize, startSector);
|
||||
partition = _FAT_partition_constructor (interface, cacheSize, SectorsPerPage, startSector);
|
||||
if (!partition) {
|
||||
_FAT_mem_free (devops);
|
||||
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) {
|
||||
return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES);
|
||||
return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE);
|
||||
}
|
||||
|
||||
void fatUnmount (const char* name) {
|
||||
@ -132,7 +131,7 @@ bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice) {
|
||||
i++)
|
||||
{
|
||||
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
|
||||
if (defaultDevice < 0) {
|
||||
defaultDevice = i;
|
||||
|
@ -37,6 +37,14 @@ static inline void* _FAT_mem_allocate (size_t 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) {
|
||||
free (mem);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ enum BPB {
|
||||
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;
|
||||
int i;
|
||||
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
|
||||
partition->cache = _FAT_cache_constructor (cacheSize, partition->disc);
|
||||
partition->cache = _FAT_cache_constructor (cacheSize, sectorsPerPage, partition->disc);
|
||||
|
||||
// Set current directory to the root
|
||||
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
|
||||
*/
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user