#define INCLUDE_FROM_VIRTUAL_FAT_C
#include "VirtualFAT.h"
static const FATBootBlock_t BootBlock =
{
.Bootstrap = {0xEB, 0x3C, 0x90},
.Description = "mkdosfs",
.SectorSize = SECTOR_SIZE_BYTES,
.SectorsPerCluster = SECTOR_PER_CLUSTER,
.ReservedSectors = 1,
.FATCopies = 2,
.RootDirectoryEntries = (SECTOR_SIZE_BYTES / sizeof(FATDirectoryEntry_t)),
.TotalSectors16 = LUN_MEDIA_BLOCKS,
.MediaDescriptor = 0xF8,
.SectorsPerFAT = 1,
.SectorsPerTrack = (LUN_MEDIA_BLOCKS % 64),
.Heads = (LUN_MEDIA_BLOCKS / 64),
.HiddenSectors = 0,
.TotalSectors32 = 0,
.PhysicalDriveNum = 0,
.ExtendedBootRecordSig = 0x29,
.VolumeSerialNumber = 0x12345678,
.VolumeLabel = "LUFA BOOT ",
.FilesystemIdentifier = "FAT12 ",
};
static FATDirectoryEntry_t FirmwareFileEntries[] =
{
[DISK_FILE_ENTRY_VolumeID] =
{
.MSDOS_Directory =
{
.Name = "LUFA BOOT ",
.Attributes = FAT_FLAG_VOLUME_NAME,
.Reserved = {0},
.CreationTime = 0,
.CreationDate = 0,
.StartingCluster = 0,
.Reserved2 = 0,
}
},
[DISK_FILE_ENTRY_FLASH_LFN] =
{
.VFAT_LongFileName =
{
.Ordinal = 1 | FAT_ORDINAL_LAST_ENTRY,
.Attribute = FAT_FLAG_LONG_FILE_NAME,
.Reserved1 = 0,
.Reserved2 = 0,
.Checksum = FAT_CHECKSUM('F','L','A','S','H',' ',' ',' ','B','I','N'),
.Unicode1 = 'F',
.Unicode2 = 'L',
.Unicode3 = 'A',
.Unicode4 = 'S',
.Unicode5 = 'H',
.Unicode6 = '.',
.Unicode7 = 'B',
.Unicode8 = 'I',
.Unicode9 = 'N',
.Unicode10 = 0,
.Unicode11 = 0,
.Unicode12 = 0,
.Unicode13 = 0,
}
},
[DISK_FILE_ENTRY_FLASH_MSDOS] =
{
.MSDOS_File =
{
.Filename = "FLASH ",
.Extension = "BIN",
.Attributes = 0,
.Reserved = {0},
.CreationTime = FAT_TIME(1, 1, 0),
.CreationDate = FAT_DATE(14, 2, 1989),
.StartingCluster = 2,
.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,
}
},
};
static const uint16_t* FLASHFileStartCluster = &FirmwareFileEntries[DISK_FILE_ENTRY_FLASH_MSDOS].MSDOS_File.StartingCluster;
static const uint16_t* EEPROMFileStartCluster = &FirmwareFileEntries[DISK_FILE_ENTRY_EEPROM_MSDOS].MSDOS_File.StartingCluster;
static uint8_t ReadEEPROMByte(const uint8_t* const Address)
{
return eeprom_read_byte(Address);
}
static void WriteEEPROMByte(uint8_t* const Address,
const uint8_t Data)
{
eeprom_update_byte(Address, Data);
}
static void UpdateFAT12ClusterEntry(uint8_t* const FATTable,
const uint16_t Index,
const uint16_t ChainEntry)
{
uint8_t FATOffset = (Index + (Index >> 1));
bool UpperNibble = ((Index & 1) != 0);
if (UpperNibble)
{
FATTable[FATOffset] = (FATTable[FATOffset] & 0x0F) | ((ChainEntry & 0x0F) << 4);
FATTable[FATOffset + 1] = (ChainEntry >> 4);
}
else
{
FATTable[FATOffset] = ChainEntry;
FATTable[FATOffset + 1] = (FATTable[FATOffset + 1] & 0xF0) | (ChainEntry >> 8);
}
}
static void UpdateFAT12ClusterChain(uint8_t* const FATTable,
const uint16_t Index,
const uint8_t ChainLength)
{
for (uint8_t i = 0; i < ChainLength; i++)
{
uint16_t CurrentCluster = Index + i;
uint16_t NextCluster = CurrentCluster + 1;
if (i == (ChainLength - 1))
NextCluster = 0xFFF;
UpdateFAT12ClusterEntry(FATTable, CurrentCluster, NextCluster);
}
}
static void ReadWriteFLASHFileBlock(const uint16_t BlockNumber,
uint8_t* BlockBuffer,
const bool Read)
{
uint16_t FileStartBlock = DISK_BLOCK_DataStartBlock + (*FLASHFileStartCluster - 2) * SECTOR_PER_CLUSTER;
uint16_t FileEndBlock = FileStartBlock + (FILE_SECTORS(FLASH_FILE_SIZE_BYTES) - 1);
if (!((BlockNumber >= FileStartBlock) && (BlockNumber <= FileEndBlock)))
return;
#if (FLASHEND > 0xFFFF)
uint32_t FlashAddress = (uint32_t)(BlockNumber - FileStartBlock) * SECTOR_SIZE_BYTES;
#else
uint16_t FlashAddress = (uint16_t)(BlockNumber - FileStartBlock) * SECTOR_SIZE_BYTES;
#endif
if (Read)
{
for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
{
#if (FLASHEND > 0xFFFF)
BlockBuffer[i] = pgm_read_byte_far(FlashAddress++);
#else
BlockBuffer[i] = pgm_read_byte(FlashAddress++);
#endif
}
}
else
{
for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i += 2)
{
if ((FlashAddress % SPM_PAGESIZE) == 0)
{
BootloaderAPI_ErasePage(FlashAddress);
}
BootloaderAPI_FillWord(FlashAddress, (BlockBuffer[i + 1] << 8) | BlockBuffer[i]);
FlashAddress += 2;
if ((FlashAddress % SPM_PAGESIZE) == 0)
{
BootloaderAPI_WritePage(FlashAddress - SPM_PAGESIZE);
}
}
}
}
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);
if (!((BlockNumber >= FileStartBlock) && (BlockNumber <= FileEndBlock)))
return;
uint16_t EEPROMAddress = (uint16_t)(BlockNumber - FileStartBlock) * SECTOR_SIZE_BYTES;
if (Read)
{
for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
BlockBuffer[i] = ReadEEPROMByte((uint8_t*)EEPROMAddress++);
}
else
{
for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
WriteEEPROMByte((uint8_t*)EEPROMAddress++, BlockBuffer[i]);
}
}
void VirtualFAT_WriteBlock(const uint16_t BlockNumber)
{
uint8_t BlockBuffer[SECTOR_SIZE_BYTES];
Endpoint_Read_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
Endpoint_ClearOUT();
switch (BlockNumber)
{
case DISK_BLOCK_BootBlock:
case DISK_BLOCK_FATBlock1:
case DISK_BLOCK_FATBlock2:
break;
case DISK_BLOCK_RootFilesBlock:
memcpy(FirmwareFileEntries, BlockBuffer, sizeof(FirmwareFileEntries));
break;
default:
ReadWriteFLASHFileBlock(BlockNumber, BlockBuffer, false);
ReadWriteEEPROMFileBlock(BlockNumber, BlockBuffer, false);
break;
}
}
void VirtualFAT_ReadBlock(const uint16_t BlockNumber)
{
uint8_t BlockBuffer[SECTOR_SIZE_BYTES];
memset(BlockBuffer, 0x00, sizeof(BlockBuffer));
switch (BlockNumber)
{
case DISK_BLOCK_BootBlock:
memcpy(BlockBuffer, &BootBlock, sizeof(FATBootBlock_t));
BlockBuffer[SECTOR_SIZE_BYTES - 2] = 0x55;
BlockBuffer[SECTOR_SIZE_BYTES - 1] = 0xAA;
break;
case DISK_BLOCK_FATBlock1:
case DISK_BLOCK_FATBlock2:
UpdateFAT12ClusterEntry(BlockBuffer, 0, 0xF00 | BootBlock.MediaDescriptor);
UpdateFAT12ClusterEntry(BlockBuffer, 1, 0xFFF);
UpdateFAT12ClusterChain(BlockBuffer, *FLASHFileStartCluster, FILE_CLUSTERS(FLASH_FILE_SIZE_BYTES));
UpdateFAT12ClusterChain(BlockBuffer, *EEPROMFileStartCluster, FILE_CLUSTERS(EEPROM_FILE_SIZE_BYTES));
break;
case DISK_BLOCK_RootFilesBlock:
memcpy(BlockBuffer, FirmwareFileEntries, sizeof(FirmwareFileEntries));
break;
default:
ReadWriteFLASHFileBlock(BlockNumber, BlockBuffer, true);
ReadWriteEEPROMFileBlock(BlockNumber, BlockBuffer, true);
break;
}
Endpoint_Write_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
Endpoint_ClearIN();
}