mirror of
https://github.com/eclipse-threadx/filex.git
synced 2026-09-14 20:55:36 +08:00
* Updated version number constants * Updated copyright headers and removed revision history
537 lines
22 KiB
C
537 lines
22 KiB
C
/***************************************************************************
|
|
* Copyright (c) 2024 Microsoft Corporation
|
|
* Copyright (c) 2026-present Eclipse ThreadX contributors
|
|
*
|
|
* This program and the accompanying materials are made available under the
|
|
* terms of the MIT License which is available at
|
|
* https://opensource.org/licenses/MIT.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
**************************************************************************/
|
|
|
|
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
/** */
|
|
/** FileX Component */
|
|
/** */
|
|
/** Utility */
|
|
/** */
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
|
|
#define FX_SOURCE_CODE
|
|
|
|
|
|
/* Include necessary system files. */
|
|
|
|
#include "fx_api.h"
|
|
#include "fx_system.h"
|
|
#include "fx_utility.h"
|
|
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _fx_utility_FAT_flush PORTABLE C */
|
|
/* 6.1.2 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* William E. Lamie, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function flushes the contents of the FAT cache to the media. */
|
|
/* 12-bit, 16-bit and 32-bit FAT writing is supported. */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* media_ptr Media control block pointer */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* return status */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* _fx_utility_16_unsigned_write Write a UINT into buffer */
|
|
/* _fx_utility_32_unsigned_read Read a ULONG from buffer */
|
|
/* _fx_utility_32_unsigned_write Write a ULONG into buffer */
|
|
/* _fx_utility_logical_sector_read Read FAT sector into memory */
|
|
/* _fx_utility_logical_sector_write Write FAT sector back to disk */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* FileX System Functions */
|
|
/* */
|
|
/**************************************************************************/
|
|
UINT _fx_utility_FAT_flush(FX_MEDIA *media_ptr)
|
|
{
|
|
|
|
ULONG FAT_sector;
|
|
ULONG byte_offset;
|
|
UCHAR *FAT_ptr;
|
|
UINT temp, i;
|
|
UINT status, index, ind;
|
|
ULONG cluster, next_cluster;
|
|
UCHAR sectors_per_bit;
|
|
INT multi_sector_entry;
|
|
ULONG sector;
|
|
|
|
#ifndef FX_MEDIA_STATISTICS_DISABLE
|
|
/* Increment the number of cache flush requests. */
|
|
media_ptr -> fx_media_fat_cache_flushes++;
|
|
#endif
|
|
|
|
/* Loop through the media's FAT cache and flush out dirty entries. */
|
|
for (index = 0; index < FX_MAX_FAT_CACHE; index++)
|
|
{
|
|
|
|
/* Determine if the entry is dirty. */
|
|
if ((media_ptr -> fx_media_fat_cache[index].fx_fat_cache_entry_dirty) == 0)
|
|
{
|
|
|
|
/* No, just advance to the next entry. */
|
|
continue;
|
|
}
|
|
|
|
/* Otherwise, the entry is indeed dirty and must be flushed out. Process
|
|
relative to the type of FAT that is being used. */
|
|
|
|
/* Pickup the contents of the FAT cache entry. */
|
|
cluster = media_ptr -> fx_media_fat_cache[index].fx_fat_cache_entry_cluster;
|
|
|
|
/* Determine which type of FAT is present. */
|
|
if (media_ptr -> fx_media_12_bit_FAT)
|
|
{
|
|
|
|
/* Calculate the byte offset to the cluster entry. */
|
|
byte_offset = (((ULONG)cluster << 1) + cluster) >> 1;
|
|
|
|
/* Calculate the FAT sector the requested FAT entry resides in. */
|
|
FAT_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
|
|
(ULONG)media_ptr -> fx_media_reserved_sectors;
|
|
|
|
/* Initialize as not written. */
|
|
multi_sector_entry = -1;
|
|
|
|
for (;;)
|
|
{
|
|
|
|
/* Pickup the FAT sector. */
|
|
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
|
|
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
|
|
|
|
/* Determine if an error occurred. */
|
|
if (status != FX_SUCCESS)
|
|
{
|
|
|
|
/* Return the error status. */
|
|
return(status);
|
|
}
|
|
|
|
/* Determine if a mulit-sector FAT update is present. */
|
|
if (multi_sector_entry != -1)
|
|
{
|
|
|
|
/* Yes, store the remaining portion of the new FAT entry in the
|
|
next FAT sector. */
|
|
|
|
/* Setup a pointer into the buffer. */
|
|
FAT_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer;
|
|
|
|
/* Pickup the cluster and next cluster. */
|
|
cluster = (media_ptr -> fx_media_fat_cache[multi_sector_entry].fx_fat_cache_entry_cluster);
|
|
next_cluster = media_ptr -> fx_media_fat_cache[multi_sector_entry].fx_fat_cache_entry_value;
|
|
|
|
/* Determine if the cluster entry is odd or even. */
|
|
if (cluster & 1)
|
|
{
|
|
|
|
/* Store the upper 8 bits of the FAT entry. */
|
|
*FAT_ptr = (UCHAR)((next_cluster >> 4) & 0xFF);
|
|
}
|
|
else
|
|
{
|
|
|
|
/* Store the upper 4 bits of the FAT entry. */
|
|
temp = ((UINT)*FAT_ptr) & 0xF0;
|
|
*FAT_ptr = (UCHAR)(temp | ((next_cluster >> 8) & 0xF));
|
|
}
|
|
|
|
/* Clear the multi-sector flag. */
|
|
multi_sector_entry = -1;
|
|
}
|
|
|
|
/* Loop through the remainder of the cache to check for multiple entries
|
|
within the same FAT sector being written out. */
|
|
for (i = index; i < FX_MAX_FAT_CACHE; i++)
|
|
{
|
|
|
|
/* Is the cache entry dirty? */
|
|
if ((media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty) == 0)
|
|
{
|
|
|
|
/* Not dirty, does not need to be flushed. */
|
|
continue;
|
|
}
|
|
|
|
/* Isolate the cluster. */
|
|
cluster = (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster);
|
|
|
|
/* Calculate the byte offset to the cluster entry. */
|
|
byte_offset = (((ULONG)cluster << 1) + cluster) >> 1;
|
|
|
|
/* Pickup the sector. */
|
|
sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
|
|
(ULONG)media_ptr -> fx_media_reserved_sectors;
|
|
|
|
/* Is it the current FAT sector? */
|
|
if (sector != FAT_sector)
|
|
{
|
|
|
|
/* Different FAT sector - not in this pass of the loop. */
|
|
continue;
|
|
}
|
|
|
|
/* Pickup new value for this FAT entry. */
|
|
next_cluster = media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value;
|
|
|
|
/* Now calculate the byte offset into this FAT sector. */
|
|
byte_offset = byte_offset -
|
|
((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
|
|
media_ptr -> fx_media_bytes_per_sector);
|
|
|
|
/* Determine if we are now past the end of the FAT buffer in memory. */
|
|
if (byte_offset == (ULONG)(media_ptr -> fx_media_bytes_per_sector - 1))
|
|
{
|
|
|
|
/* Yes, we need to read the next sector */
|
|
multi_sector_entry = (INT)i;
|
|
}
|
|
|
|
/* Setup a pointer into the buffer. */
|
|
FAT_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
|
|
|
|
/* Clear the dirty flag. */
|
|
media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty = 0;
|
|
|
|
/* Determine if the cluster entry is odd or even. */
|
|
if (cluster & 1)
|
|
{
|
|
|
|
/* Odd cluster number. */
|
|
|
|
/* Pickup the upper nibble of the FAT entry. */
|
|
|
|
/* First, set the lower nibble of the FAT entry. */
|
|
temp = (((UINT)*FAT_ptr) & 0x0F);
|
|
*FAT_ptr = (UCHAR)(temp | ((next_cluster << 4) & 0xF0));
|
|
|
|
/* Determine if this is a mulit-sector entry. */
|
|
if ((multi_sector_entry) == (INT)i)
|
|
{
|
|
|
|
/* Yes, requires multiple sector - will write rest of the part later. */
|
|
continue;
|
|
}
|
|
|
|
/* Move to the next byte of the FAT entry. */
|
|
FAT_ptr++;
|
|
|
|
/* Store the upper 8 bits of the FAT entry. */
|
|
*FAT_ptr = (UCHAR)((next_cluster >> 4) & 0xFF);
|
|
}
|
|
else
|
|
{
|
|
|
|
/* Even cluster number. */
|
|
|
|
/* Store the lower byte of the FAT entry. */
|
|
*FAT_ptr = (UCHAR)(next_cluster & 0xFF);
|
|
|
|
/* Determine if this is a mulit-sector entry. */
|
|
if ((multi_sector_entry) == (INT)i)
|
|
{
|
|
|
|
/* Yes, requires multiple sector - will write rest of the part later. */
|
|
continue;
|
|
}
|
|
|
|
/* Move to the next nibble of the FAT entry. */
|
|
FAT_ptr++;
|
|
|
|
/* Store the upper 4 bits of the FAT entry. */
|
|
temp = ((UINT)*FAT_ptr) & 0xF0;
|
|
*FAT_ptr = (UCHAR)(temp | ((next_cluster >> 8) & 0xF));
|
|
}
|
|
}
|
|
|
|
/* First, write out the current sector. */
|
|
status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) FAT_sector,
|
|
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
|
|
/* Determine if an error occurred. */
|
|
if (status != FX_SUCCESS)
|
|
{
|
|
|
|
/* Return the error status. */
|
|
return(status);
|
|
}
|
|
|
|
/* Mark the FAT sector update bit map to indicate this sector has been written. */
|
|
if (media_ptr -> fx_media_sectors_per_FAT % (FX_FAT_MAP_SIZE << 3) == 0)
|
|
{
|
|
sectors_per_bit = (UCHAR)((UINT)media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3));
|
|
}
|
|
else
|
|
{
|
|
sectors_per_bit = (UCHAR)((UINT)media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3) + 1);
|
|
}
|
|
|
|
/* Check for invalid value. */
|
|
if (sectors_per_bit == 0)
|
|
{
|
|
|
|
/* Invalid media, return error. */
|
|
return(FX_MEDIA_INVALID);
|
|
}
|
|
|
|
ind = ((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) >> 3;
|
|
media_ptr -> fx_media_fat_secondary_update_map[ind] =
|
|
(UCHAR)((INT)media_ptr -> fx_media_fat_secondary_update_map[ind]
|
|
| (1 <<(((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) & 7)));
|
|
|
|
/* Determine if the multi-sector flag is set. */
|
|
if (multi_sector_entry != -1)
|
|
{
|
|
|
|
/* Yes, position to the next sector and read it in. */
|
|
FAT_sector++;
|
|
}
|
|
else
|
|
{
|
|
|
|
/* No, we are finished with this loop. */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (!media_ptr -> fx_media_32_bit_FAT)
|
|
{
|
|
|
|
/* 16-bit FAT is present. */
|
|
|
|
/* Calculate the byte offset to the cluster entry. */
|
|
byte_offset = (((ULONG)cluster) << 1);
|
|
|
|
/* Calculate the FAT sector the requested FAT entry resides in. */
|
|
FAT_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
|
|
(ULONG)media_ptr -> fx_media_reserved_sectors;
|
|
|
|
/* Read the FAT sector. */
|
|
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
|
|
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
|
|
|
|
/* Determine if an error occurred. */
|
|
if (status != FX_SUCCESS)
|
|
{
|
|
|
|
/* Return the error status. */
|
|
return(status);
|
|
}
|
|
|
|
/* Loop through the remainder of the cache to check for multiple entries
|
|
within the same FAT sector being written out. */
|
|
for (i = index; i < FX_MAX_FAT_CACHE; i++)
|
|
{
|
|
|
|
/* Determine if the entry is dirty. */
|
|
if (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty == 0)
|
|
{
|
|
|
|
/* Not dirty, does not need to be flushed. */
|
|
continue;
|
|
}
|
|
|
|
/* Isolate the cluster. */
|
|
cluster = (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster);
|
|
|
|
/* Calculate the byte offset to the cluster entry. */
|
|
byte_offset = (((ULONG)cluster) * 2);
|
|
|
|
/* Pickup the sector. */
|
|
sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
|
|
(ULONG)media_ptr -> fx_media_reserved_sectors;
|
|
|
|
/* Is it the current FAT sector? */
|
|
if (sector != FAT_sector)
|
|
{
|
|
|
|
/* Different FAT sector - not in this pass of the loop. */
|
|
continue;
|
|
}
|
|
|
|
/* Now calculate the byte offset into this FAT sector. */
|
|
byte_offset = byte_offset -
|
|
((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
|
|
media_ptr -> fx_media_bytes_per_sector);
|
|
|
|
/* Setup a pointer into the buffer. */
|
|
FAT_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
|
|
|
|
/* Pickup new value for this FAT entry. */
|
|
next_cluster = media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value;
|
|
|
|
/* Store the FAT entry. */
|
|
_fx_utility_16_unsigned_write(FAT_ptr, (UINT)next_cluster);
|
|
|
|
/* Clear the dirty flag. */
|
|
media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty = 0;
|
|
}
|
|
|
|
/* Write the last written FAT sector out. */
|
|
status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) FAT_sector,
|
|
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
|
|
|
|
/* Determine if an error occurred. */
|
|
if (status != FX_SUCCESS)
|
|
{
|
|
/* Return the error status. */
|
|
return(status);
|
|
}
|
|
|
|
/* Mark the FAT sector update bit map to indicate this sector has been
|
|
written. */
|
|
if (media_ptr -> fx_media_sectors_per_FAT % (FX_FAT_MAP_SIZE << 3) == 0)
|
|
{
|
|
sectors_per_bit = (UCHAR)(media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3));
|
|
}
|
|
else
|
|
{
|
|
sectors_per_bit = (UCHAR)((media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3)) + 1);
|
|
}
|
|
ind = ((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) >> 3;
|
|
media_ptr -> fx_media_fat_secondary_update_map[ind] =
|
|
(UCHAR)((INT)media_ptr -> fx_media_fat_secondary_update_map[ind]
|
|
| (1 <<(((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) & 7)));
|
|
}
|
|
else
|
|
{
|
|
|
|
/* 32-bit FAT is present. */
|
|
|
|
/* Calculate the byte offset to the cluster entry. */
|
|
byte_offset = (((ULONG)cluster) * 4);
|
|
|
|
/* Calculate the FAT sector the requested FAT entry resides in. */
|
|
FAT_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
|
|
(ULONG)media_ptr -> fx_media_reserved_sectors;
|
|
|
|
/* Read the FAT sector. */
|
|
status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
|
|
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
|
|
|
|
/* Determine if an error occurred. */
|
|
if (status != FX_SUCCESS)
|
|
{
|
|
|
|
/* Return the error status. */
|
|
return(status);
|
|
}
|
|
|
|
/* Loop through the remainder of the cache to check for multiple entries
|
|
within the same FAT sector being written out. */
|
|
for (i = index; i < FX_MAX_FAT_CACHE; i++)
|
|
{
|
|
|
|
/* Determine if the entry is dirty. */
|
|
if (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty == 0)
|
|
{
|
|
|
|
/* Not dirty, does not need to be flushed. */
|
|
continue;
|
|
}
|
|
|
|
/* Isolate the cluster. */
|
|
cluster = (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster);
|
|
|
|
/* Calculate the byte offset to the cluster entry. */
|
|
byte_offset = (((ULONG)cluster) * 4);
|
|
|
|
/* Pickup the sector. */
|
|
sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
|
|
(ULONG)media_ptr -> fx_media_reserved_sectors;
|
|
|
|
/* Is it the current FAT sector? */
|
|
if (sector != FAT_sector)
|
|
{
|
|
|
|
/* Different FAT sector - not in this pass of the loop. */
|
|
continue;
|
|
}
|
|
|
|
/* Now calculate the byte offset into this FAT sector. */
|
|
byte_offset = byte_offset -
|
|
((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
|
|
media_ptr -> fx_media_bytes_per_sector);
|
|
|
|
/* Setup a pointer into the buffer. */
|
|
FAT_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
|
|
|
|
/* Pickup new value for this FAT entry. */
|
|
next_cluster = media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value;
|
|
|
|
/* Store the FAT entry. */
|
|
_fx_utility_32_unsigned_write(FAT_ptr, next_cluster);
|
|
|
|
/* Clear the dirty flag. */
|
|
media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty = 0;
|
|
}
|
|
|
|
/* Write the last written FAT sector out. */
|
|
status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) FAT_sector,
|
|
media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
|
|
|
|
/* Determine if an error occurred. */
|
|
if (status != FX_SUCCESS)
|
|
{
|
|
|
|
/* Return the error status. */
|
|
return(status);
|
|
}
|
|
|
|
|
|
/* Mark the FAT sector update bit map to indicate this sector has been
|
|
written. */
|
|
if (media_ptr -> fx_media_sectors_per_FAT % (FX_FAT_MAP_SIZE << 3) == 0)
|
|
{
|
|
sectors_per_bit = (UCHAR)(media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3));
|
|
}
|
|
else
|
|
{
|
|
sectors_per_bit = (UCHAR)((media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3)) + 1);
|
|
}
|
|
ind = ((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) >> 3;
|
|
media_ptr -> fx_media_fat_secondary_update_map[ind] =
|
|
(UCHAR)((INT)media_ptr -> fx_media_fat_secondary_update_map[ind]
|
|
| (1 <<(((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) & 7)));
|
|
}
|
|
}
|
|
|
|
#ifdef FX_ENABLE_FAULT_TOLERANT
|
|
|
|
/* While fault_tolerant is enabled, this function will be called before the return of all APIs. */
|
|
if (media_ptr -> fx_media_fault_tolerant_enabled)
|
|
{
|
|
|
|
/* Delete the record of FAT sector since all FAT entries are flushed. */
|
|
media_ptr -> fx_media_fault_tolerant_cached_FAT_sector = 0;
|
|
}
|
|
#endif /* FX_ENABLE_FAULT_TOLERANT */
|
|
|
|
/* Return successful status. */
|
|
return(FX_SUCCESS);
|
|
}
|
|
|