Add EEPROM read/write support to the Mass Storage class bootloader.

pull/1469/head
Dean Camera 12 years ago
parent 829ecefe41
commit 7251da6581

@ -95,61 +95,110 @@ static FATDirectoryEntry_t FirmwareFileEntries[] =
/* VFAT Long File Name entry for the virtual firmware file; required to /* VFAT Long File Name entry for the virtual firmware file; required to
* prevent corruption from systems that are unable to detect the device * prevent corruption from systems that are unable to detect the device
* as being a legacy MSDOS style FAT12 volume. */ * as being a legacy MSDOS style FAT12 volume. */
[DISK_FILE_ENTRY_FirmwareLFN] = [DISK_FILE_ENTRY_FLASH_LFN] =
{ {
.VFAT_LongFileName = .VFAT_LongFileName =
{ {
.Ordinal = FAT_ORDINAL_LAST_ENTRY | 1, .Ordinal = 1 | FAT_ORDINAL_LAST_ENTRY,
.Attribute = FAT_FLAG_LONG_FILE_NAME, .Attribute = FAT_FLAG_LONG_FILE_NAME,
.Reserved1 = 0, .Reserved1 = 0,
.Reserved2 = 0, .Reserved2 = 0,
.Checksum = 0x57, .Checksum = FAT_CHECKSUM('F','L','A','S','H',' ',' ',' ','B','I','N'),
.Unicode1 = 'F', .Unicode1 = 'F',
.Unicode2 = 'I', .Unicode2 = 'L',
.Unicode3 = 'R', .Unicode3 = 'A',
.Unicode4 = 'M', .Unicode4 = 'S',
.Unicode5 = 'W', .Unicode5 = 'H',
.Unicode6 = 'A', .Unicode6 = '.',
.Unicode7 = 'R', .Unicode7 = 'B',
.Unicode8 = 'E', .Unicode8 = 'I',
.Unicode9 = '.', .Unicode9 = 'N',
.Unicode10 = 'B', .Unicode10 = 0,
.Unicode11 = 'I', .Unicode11 = 0,
.Unicode12 = 'N', .Unicode12 = 0,
.Unicode13 = 0, .Unicode13 = 0,
} }
}, },
/* MSDOS file entry for the virtual Firmware image. */ /* MSDOS file entry for the virtual Firmware image. */
[DISK_FILE_ENTRY_FirmwareMSDOS] = [DISK_FILE_ENTRY_FLASH_MSDOS] =
{ {
.MSDOS_File = .MSDOS_File =
{ {
.Filename = "FIRMWARE", .Filename = "FLASH ",
.Extension = "BIN", .Extension = "BIN",
.Attributes = 0, .Attributes = 0,
.Reserved = {0}, .Reserved = {0},
.CreationTime = FAT_TIME(1, 1, 0), .CreationTime = FAT_TIME(1, 1, 0),
.CreationDate = FAT_DATE(14, 2, 1989), .CreationDate = FAT_DATE(14, 2, 1989),
.StartingCluster = 2, .StartingCluster = 2,
.FileSizeBytes = FIRMWARE_FILE_SIZE_BYTES, .FileSizeBytes = FLASH_FILE_SIZE_BYTES,
}
},
[DISK_FILE_ENTRY_EEPROM_LFN] =
{
.VFAT_LongFileName =
{
.Ordinal = 1 | FAT_ORDINAL_LAST_ENTRY,
.Attribute = FAT_FLAG_LONG_FILE_NAME,
.Reserved1 = 0,
.Reserved2 = 0,
.Checksum = FAT_CHECKSUM('E','E','P','R','O','M',' ',' ','B','I','N'),
.Unicode1 = 'E',
.Unicode2 = 'E',
.Unicode3 = 'P',
.Unicode4 = 'R',
.Unicode5 = 'O',
.Unicode6 = 'M',
.Unicode7 = '.',
.Unicode8 = 'B',
.Unicode9 = 'I',
.Unicode10 = 'N',
.Unicode11 = 0,
.Unicode12 = 0,
.Unicode13 = 0,
}
},
[DISK_FILE_ENTRY_EEPROM_MSDOS] =
{
.MSDOS_File =
{
.Filename = "EEPROM ",
.Extension = "BIN",
.Attributes = 0,
.Reserved = {0},
.CreationTime = FAT_TIME(1, 1, 0),
.CreationDate = FAT_DATE(14, 2, 1989),
.StartingCluster = 2 + FILE_CLUSTERS(FLASH_FILE_SIZE_BYTES),
.FileSizeBytes = EEPROM_FILE_SIZE_BYTES,
} }
}, },
}; };
/** Starting cluster of the virtual firmware file on disk, tracked so that the /** Starting cluster of the virtual FLASH.BIN file on disk, tracked so that the
* offset from the start of the data sector can be determined. On Windows * offset from the start of the data sector can be determined. On Windows
* systems files are usually replaced using the original file's disk clusters, * systems files are usually replaced using the original file's disk clusters,
* while Linux appears to overwrite with an offset which must be compensated for. * while Linux appears to overwrite with an offset which must be compensated for.
*/ */
static uint16_t* FileStartCluster = &FirmwareFileEntries[DISK_FILE_ENTRY_FirmwareMSDOS].MSDOS_File.StartingCluster; static uint16_t* FLASHFileStartCluster = &FirmwareFileEntries[DISK_FILE_ENTRY_FLASH_MSDOS].MSDOS_File.StartingCluster;
/** Starting cluster of the virtual EEPROM.BIN file on disk, tracked so that the
* offset from the start of the data sector can be determined. On Windows
* systems files are usually replaced using the original file's disk clusters,
* while Linux appears to overwrite with an offset which must be compensated for.
*/
static uint16_t* EEPROMFileStartCluster = &FirmwareFileEntries[DISK_FILE_ENTRY_EEPROM_MSDOS].MSDOS_File.StartingCluster;
/** Updates a FAT12 cluster entry in the FAT file table with the specified next /** Updates a FAT12 cluster entry in the FAT file table with the specified next
* chain index. If the cluster is the last in the file chain, the magic value * chain index. If the cluster is the last in the file chain, the magic value
* 0xFFF is used. * \c 0xFFF should be used.
* *
* \note FAT data cluster indexes are offset by 2, so that cluster 2 is the * \note FAT data cluster indexes are offset by 2, so that cluster 2 is the
* first file data cluster on the disk. See the FAT specification. * first file data cluster on the disk. See the FAT specification.
@ -180,21 +229,48 @@ static void UpdateFAT12ClusterEntry(uint8_t* const FATTable,
} }
} }
/** Updates a FAT12 cluster chain in the FAT file table with a linear chain of
* the specified length.
*
* \note FAT data cluster indexes are offset by 2, so that cluster 2 is the
* first file data cluster on the disk. See the FAT specification.
*
* \param[out] FATTable Pointer to the FAT12 allocation table
* \param[in] Index Index of the start of the cluster chain to update
* \param[in] ChainLength Length of the chain to write, in clusters
*/
static void UpdateFAT12ClusterChain(uint8_t* const FATTable,
const uint16_t Index,
const uint16_t ChainLength)
{
for (uint16_t i = 0; i < ChainLength; i++)
{
uint16_t CurrentCluster = Index + i;
uint16_t NextCluster = CurrentCluster + 1;
/* Mark last cluster as end of file */
if (i == (ChainLength - 1))
NextCluster = 0xFFF;
UpdateFAT12ClusterEntry(FATTable, CurrentCluster, NextCluster);
}
}
/** Reads or writes a block of data from/to the physical device FLASH using a /** Reads or writes a block of data from/to the physical device FLASH using a
* block buffer stored in RAM, if the requested block is within the virtual * block buffer stored in RAM, if the requested block is within the virtual
* firmware file's sector ranges in the emulated FAT file system. * firmware file's sector ranges in the emulated FAT file system.
* *
* \param[in] BlockNumber Physical disk block to read from * \param[in] BlockNumber Physical disk block to read from/write to
* \param[in,out] BlockBuffer Pointer to the start of the block buffer in RAM * \param[in,out] BlockBuffer Pointer to the start of the block buffer in RAM
* \param[in] Read If \c true, the requested block is read, if * \param[in] Read If \c true, the requested block is read, if
* \c false, the requested block is written * \c false, the requested block is written
*/ */
static void ReadWriteFirmwareFileBlock(const uint16_t BlockNumber, static void ReadWriteFLASHFileBlock(const uint16_t BlockNumber,
uint8_t* BlockBuffer, uint8_t* BlockBuffer,
const bool Read) const bool Read)
{ {
uint16_t FileStartBlock = DISK_BLOCK_DataStartBlock + (*FileStartCluster - 2) * SECTOR_PER_CLUSTER; uint16_t FileStartBlock = DISK_BLOCK_DataStartBlock + (*FLASHFileStartCluster - 2) * SECTOR_PER_CLUSTER;
uint16_t FileEndBlock = FileStartBlock + (FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES) - 1); uint16_t FileEndBlock = FileStartBlock + (FILE_SECTORS(FLASH_FILE_SIZE_BYTES) - 1);
/* Range check the write request - abort if requested block is not within the /* Range check the write request - abort if requested block is not within the
* virtual firmware file sector range */ * virtual firmware file sector range */
@ -243,6 +319,43 @@ static void ReadWriteFirmwareFileBlock(const uint16_t BlockNumber,
} }
} }
/** Reads or writes a block of data from/to the physical device EEPROM using a
* block buffer stored in RAM, if the requested block is within the virtual
* firmware file's sector ranges in the emulated FAT file system.
*
* \param[in] BlockNumber Physical disk block to read from/write to
* \param[in,out] BlockBuffer Pointer to the start of the block buffer in RAM
* \param[in] Read If \c true, the requested block is read, if
* \c false, the requested block is written
*/
static void ReadWriteEEPROMFileBlock(const uint16_t BlockNumber,
uint8_t* BlockBuffer,
const bool Read)
{
uint16_t FileStartBlock = DISK_BLOCK_DataStartBlock + (*EEPROMFileStartCluster - 2) * SECTOR_PER_CLUSTER;
uint16_t FileEndBlock = FileStartBlock + (FILE_SECTORS(EEPROM_FILE_SIZE_BYTES) - 1);
/* Range check the write request - abort if requested block is not within the
* virtual firmware file sector range */
if (!((BlockNumber >= FileStartBlock) && (BlockNumber <= FileEndBlock)))
return;
uint16_t EEPROMAddress = (uint16_t)(BlockNumber - FileStartBlock) * SECTOR_SIZE_BYTES;
if (Read)
{
/* Read out the mapped block of data from the device's EEPROM */
for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
BlockBuffer[i] = eeprom_read_byte((void*)EEPROMAddress++);
}
else
{
/* Write out the mapped block of data to the device's EEPROM */
for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
eeprom_update_byte((void*)EEPROMAddress++, BlockBuffer[i]);
}
}
/** Writes a block of data to the virtual FAT filesystem, from the USB Mass /** Writes a block of data to the virtual FAT filesystem, from the USB Mass
* Storage interface. * Storage interface.
* *
@ -272,7 +385,8 @@ void VirtualFAT_WriteBlock(const uint16_t BlockNumber)
break; break;
default: default:
ReadWriteFirmwareFileBlock(BlockNumber, BlockBuffer, false); ReadWriteFLASHFileBlock(BlockNumber, BlockBuffer, false);
ReadWriteEEPROMFileBlock(BlockNumber, BlockBuffer, false);
break; break;
} }
@ -307,18 +421,11 @@ void VirtualFAT_ReadBlock(const uint16_t BlockNumber)
/* Cluster 1: Reserved */ /* Cluster 1: Reserved */
UpdateFAT12ClusterEntry(BlockBuffer, 1, 0xFFF); UpdateFAT12ClusterEntry(BlockBuffer, 1, 0xFFF);
/* Cluster 2 onwards: Cluster chain of FIRMWARE.BIN */ /* Cluster 2 onwards: Cluster chain of FLASH.BIN */
for (uint16_t i = 0; i <= FILE_CLUSTERS(FIRMWARE_FILE_SIZE_BYTES); i++) UpdateFAT12ClusterChain(BlockBuffer, *FLASHFileStartCluster, FILE_CLUSTERS(FLASH_FILE_SIZE_BYTES));
{
uint16_t CurrentCluster = *FileStartCluster + i;
uint16_t NextCluster = CurrentCluster + 1;
/* Mark last cluster as end of file */
if (i == FILE_CLUSTERS(FIRMWARE_FILE_SIZE_BYTES))
NextCluster = 0xFFF;
UpdateFAT12ClusterEntry(BlockBuffer, CurrentCluster, NextCluster); /* Cluster 2+n onwards: Cluster chain of EEPROM.BIN */
} UpdateFAT12ClusterChain(BlockBuffer, *EEPROMFileStartCluster, FILE_CLUSTERS(EEPROM_FILE_SIZE_BYTES));
break; break;
@ -328,7 +435,8 @@ void VirtualFAT_ReadBlock(const uint16_t BlockNumber)
break; break;
default: default:
ReadWriteFirmwareFileBlock(BlockNumber, BlockBuffer, true); ReadWriteFLASHFileBlock(BlockNumber, BlockBuffer, true);
ReadWriteEEPROMFileBlock(BlockNumber, BlockBuffer, true);
break; break;
} }

@ -40,8 +40,11 @@
#include "../BootloaderAPI.h" #include "../BootloaderAPI.h"
/* Macros: */ /* Macros: */
/** Size of the virtual FIRMWARE.BIN file in bytes. */ /** Size of the virtual FLASH.BIN file in bytes. */
#define FIRMWARE_FILE_SIZE_BYTES (FLASHEND - (FLASHEND - BOOT_START_ADDR) - AUX_BOOT_SECTION_SIZE) #define FLASH_FILE_SIZE_BYTES (FLASHEND - (FLASHEND - BOOT_START_ADDR) - AUX_BOOT_SECTION_SIZE)
/** Size of the virtual EEPROM.BIN file in bytes. */
#define EEPROM_FILE_SIZE_BYTES E2END
/** Number of sectors that comprise a single logical disk cluster. */ /** Number of sectors that comprise a single logical disk cluster. */
#define SECTOR_PER_CLUSTER 4 #define SECTOR_PER_CLUSTER 4
@ -69,7 +72,7 @@
#define FILE_CLUSTERS(size) ((size / CLUSTER_SIZE_BYTES) + ((size % CLUSTER_SIZE_BYTES) ? 1 : 0)) #define FILE_CLUSTERS(size) ((size / CLUSTER_SIZE_BYTES) + ((size % CLUSTER_SIZE_BYTES) ? 1 : 0))
/** Total number of logical sectors/blocks on the disk. */ /** Total number of logical sectors/blocks on the disk. */
#define LUN_MEDIA_BLOCKS (FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES) + 32) #define LUN_MEDIA_BLOCKS (FILE_SECTORS(FLASH_FILE_SIZE_BYTES) + FILE_SECTORS(EEPROM_FILE_SIZE_BYTES) + 32)
/** Converts a given time in HH:MM:SS format to a FAT filesystem time. /** Converts a given time in HH:MM:SS format to a FAT filesystem time.
* *
@ -94,6 +97,34 @@
*/ */
#define FAT_DATE(dd, mm, yyyy) (((yyyy - 1980) << 9) | (mm << 5) | (dd << 0)) #define FAT_DATE(dd, mm, yyyy) (((yyyy - 1980) << 9) | (mm << 5) | (dd << 0))
/** Bit-rotates a given 8-bit value once to the right.
*
* \param x Value to rotate right once
*
* \return Bit-rotated input value, rotated once to the right.
*/
#define _ROT8(x) ((((x) & 0xFE) >> 1) | (((x) & 1) ? 0x80 : 0x00))
/** Computes the LFN entry checksum of a MSDOS 8.3 format file entry,
* to associate a LFN entry with its short file entry.
*
* \param n0 MSDOS Filename character 1
* \param n1 MSDOS Filename character 2
* \param n2 MSDOS Filename character 3
* \param n3 MSDOS Filename character 4
* \param n4 MSDOS Filename character 5
* \param n5 MSDOS Filename character 6
* \param n6 MSDOS Filename character 7
* \param n7 MSDOS Filename character 8
* \param e0 MSDOS Extension character 1
* \param e1 MSDOS Extension character 2
* \param e2 MSDOS Extension character 3
*
* \return LFN checksum of the given MSDOS 8.3 filename.
*/
#define FAT_CHECKSUM(n0, n1, n2, n3, n4, n5, n6, n7, e0, e1, e2) \
(uint8_t)(_ROT8(_ROT8(_ROT8(_ROT8(_ROT8(_ROT8(_ROT8(_ROT8(_ROT8(_ROT8(n0)+n1)+n2)+n3)+n4)+n5)+n6)+n7)+e0)+e1)+e2)
/** \name FAT Filesystem Flags */ /** \name FAT Filesystem Flags */
//@{ //@{
/** FAT attribute flag to indicate a read-only file. */ /** FAT attribute flag to indicate a read-only file. */
@ -129,10 +160,14 @@
{ {
/** Volume ID directory entry, giving the name of the virtual disk. */ /** Volume ID directory entry, giving the name of the virtual disk. */
DISK_FILE_ENTRY_VolumeID = 0, DISK_FILE_ENTRY_VolumeID = 0,
/** Long File Name FAT file entry of the virtual firmware image file. */ /** Long File Name FAT file entry of the virtual FLASH.BIN image file. */
DISK_FILE_ENTRY_FirmwareLFN = 1, DISK_FILE_ENTRY_FLASH_LFN = 1,
/** Legacy MSDOS FAT file entry of the virtual firmware image file. */ /** Legacy MSDOS FAT file entry of the virtual FLASH.BIN image file. */
DISK_FILE_ENTRY_FirmwareMSDOS = 2, DISK_FILE_ENTRY_FLASH_MSDOS = 2,
/** Long File Name FAT file entry of the virtual EEPROM.BIN image file. */
DISK_FILE_ENTRY_EEPROM_LFN = 3,
/** Legacy MSDOS FAT file entry of the virtual EEPROM.BIN image file. */
DISK_FILE_ENTRY_EEPROM_MSDOS = 4,
}; };
/** Enum for the physical disk blocks of the virtual disk. */ /** Enum for the physical disk blocks of the virtual disk. */
@ -243,9 +278,17 @@
const uint16_t Index, const uint16_t Index,
const uint16_t ChainEntry) AUX_BOOT_SECTION; const uint16_t ChainEntry) AUX_BOOT_SECTION;
static void ReadWriteFirmwareFileBlock(const uint16_t BlockNumber, static void UpdateFAT12ClusterChain(uint8_t* const FATTable,
uint8_t* BlockBuffer, const uint16_t StartIndex,
const bool Read) AUX_BOOT_SECTION; const uint16_t ChainLength) AUX_BOOT_SECTION;
static void ReadWriteFLASHFileBlock(const uint16_t BlockNumber,
uint8_t* BlockBuffer,
const bool Read) AUX_BOOT_SECTION;
static void ReadWriteEEPROMFileBlock(const uint16_t BlockNumber,
uint8_t* BlockBuffer,
const bool Read) AUX_BOOT_SECTION;
#endif #endif
void VirtualFAT_WriteBlock(const uint16_t BlockNumber) AUX_BOOT_SECTION; void VirtualFAT_WriteBlock(const uint16_t BlockNumber) AUX_BOOT_SECTION;

Loading…
Cancel
Save