{
.Bootstrap = {0xEB, 0x3C, 0x90},
.Description = "mkdosfs",
- .BlockSize = VIRTUAL_MEMORY_BLOCK_SIZE,
- .BlocksPerAllocationUnit = ALLOCATION_UNIT_BLOCKS,
- .ReservedBlocks = 1,
+ .SectorSize = SECTOR_SIZE_BYTES,
+ .SectorsPerCluster = SECTOR_PER_CLUSTER,
+ .ReservedSectors = 1,
.FATCopies = 2,
- .RootDirectoryEntries = 512,
- .TotalBlocks16 = LUN_MEDIA_BLOCKS,
+ .RootDirectoryEntries = (SECTOR_SIZE_BYTES / sizeof(FATDirectoryEntry_t)),
+ .TotalSectors16 = LUN_MEDIA_BLOCKS,
.MediaDescriptor = 0xF8,
- .BlocksPerFAT = 1,
- .BlocksPerTrack = 32,
- .Heads = 64,
- .HiddenBlocks = 0,
- .TotalBlocks32 = 0,
+ .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 = "FAT16 ",
+ .FilesystemIdentifier = "FAT12 ",
.BootstrapProgram = {0},
.MagicSignature = 0xAA55,
};
static FATDirectoryEntry_t FirmwareFileEntry =
{
- .Filename = "Firmware",
- .Extension = "bin",
+ .Filename = "FIRMWARE",
+ .Extension = "BIN",
.Attributes = 0,
.Reserved = {0},
- .CreationTime = (1 << 11) | (1 << 5),
- .CreationDate = (9 << 9) | (2 << 5) | (14 << 0),
- .StartingCluster = 4,
- .FileSize = (FLASHEND + 1UL),
+ .CreationTime = FAT_TIME(1, 1, 0),
+ .CreationDate = FAT_DATE(14, 2, 1989),
+ .StartingCluster = 2,
+ .FileSizeBytes = FIRMWARE_FILE_SIZE,
};
-static void WriteBlock(uint16_t BlockNumber)
+
+static void UpdateFAT12ClusterEntry(uint8_t* FATTable,
+ const uint16_t Index,
+ const uint16_t ChainEntry)
+{
+ /* Calculate the starting offset of the cluster entry in the FAT12 table */
+ uint8_t FATOffset = (Index * 3) / 2;
+ bool UpperNibble = (((Index * 3) % 2) != 0);
+
+ /* Check if the start of the entry is at an upper nibble of the byte, fill
+ * out FAT12 entry as required */
+ if (UpperNibble)
+ {
+ FATTable[FATOffset] = (FATTable[FATOffset] & 0x0F) | ((ChainEntry & 0x0F) << 4);
+ FATTable[FATOffset + 1] = (ChainEntry >> 4);
+ }
+ else
+ {
+ FATTable[FATOffset] = ChainEntry;
+ FATTable[FATOffset + 1] = (FATTable[FATOffset] & 0xF0) | (ChainEntry >> 8);
+ }
+}
+
+static void WriteBlock(const uint16_t BlockNumber)
{
- uint8_t BlockBuffer[512];
+ uint8_t BlockBuffer[SECTOR_SIZE_BYTES];
/* Wait until endpoint is ready before continuing */
if (Endpoint_WaitUntilReady())
Endpoint_Read_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
Endpoint_ClearOUT();
- // TODO: Write to FLASH
+ if ((BlockNumber >= 4) && (BlockNumber < (4 + (FIRMWARE_FILE_SIZE / SECTOR_SIZE_BYTES))))
+ {
+ uint32_t WriteFlashAddress = (uint32_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
+
+ for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i += 2)
+ {
+ /* Disallow writing to the bootloader section */
+ if (WriteFlashAddress > BOOT_START_ADDR)
+ continue;
+
+ if ((WriteFlashAddress % SPM_PAGESIZE) == 0)
+ {
+ /* Erase the given FLASH page, ready to be programmed */
+ boot_page_erase(WriteFlashAddress);
+ boot_spm_busy_wait();
+ }
+
+ /* Write the next data word to the FLASH page */
+ boot_page_fill(WriteFlashAddress, (BlockBuffer[i + 1] << 8) | BlockBuffer[i]);
+ WriteFlashAddress += 2;
+
+ if ((WriteFlashAddress % SPM_PAGESIZE) == 0)
+ {
+ /* Write the filled FLASH page to memory */
+ boot_page_write(WriteFlashAddress - SPM_PAGESIZE);
+ boot_spm_busy_wait();
+ }
+ }
+ }
}
-static void ReadBlock(uint16_t BlockNumber)
+static void ReadBlock(const uint16_t BlockNumber)
{
- uint8_t BlockBuffer[512];
+ uint8_t BlockBuffer[SECTOR_SIZE_BYTES];
memset(BlockBuffer, 0x00, sizeof(BlockBuffer));
switch (BlockNumber)
case 1:
case 2:
/* Cluster 0: Media type/Reserved */
- ((uint16_t*)&BlockBuffer)[0] = 0xFF00 | BootBlock.MediaDescriptor;
+ UpdateFAT12ClusterEntry(BlockBuffer, 0, 0xF00 | BootBlock.MediaDescriptor);
/* Cluster 1: Reserved */
- ((uint16_t*)&BlockBuffer)[1] = 0xFFFF;
-
- /* Cluster 2: Reserved */
- ((uint16_t*)&BlockBuffer)[2] = 0xFFFF;
+ UpdateFAT12ClusterEntry(BlockBuffer, 1, 0xFFF);
- /* Cluster 3: FIRMWARE.BIN File Entry */
- ((uint16_t*)&BlockBuffer)[3] = 0xFFFF;
-
- /* Cluster 4 onwards: Cluster chain of FIRMWARE.BIN */
- for (uint16_t i = 0; i < ((FLASHEND + 1) / (VIRTUAL_MEMORY_BLOCK_SIZE * ALLOCATION_UNIT_BLOCKS)); i++)
- {
- ((uint16_t*)&BlockBuffer)[i + 4] = i + 5;
- }
+ /* Cluster 2 onwards: Cluster chain of FIRMWARE.BIN */
+ for (uint16_t i = 0; i < FILE_CLUSTERS(FIRMWARE_FILE_SIZE); i++)
+ UpdateFAT12ClusterEntry(BlockBuffer, i+2, i+3);
/* Mark last cluster as end of file */
- ((uint16_t*)&BlockBuffer)[((FLASHEND + 1) / (VIRTUAL_MEMORY_BLOCK_SIZE * ALLOCATION_UNIT_BLOCKS)) + 4] = 0xFFFF;
+ UpdateFAT12ClusterEntry(BlockBuffer, FILE_CLUSTERS(FIRMWARE_FILE_SIZE) + 1, 0xFFF);
break;
case 3:
break;
default:
+ if ((BlockNumber >= 4) && (BlockNumber < (4 + (FIRMWARE_FILE_SIZE / SECTOR_SIZE_BYTES))))
+ {
+ uint32_t ReadFlashAddress = (uint32_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
+
+ for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
+ BlockBuffer[i] = pgm_read_byte_far(ReadFlashAddress++);
+ }
+
break;
}
{
uint16_t CurrentBlock = (uint16_t)BlockAddress;
+ /* Emulated FAT is performed per-block, pass each requested block index
+ * to the emulation function */
while (TotalBlocks--)
WriteBlock(CurrentBlock++);
}
{
uint16_t CurrentBlock = (uint16_t)BlockAddress;
+ /* Emulated FAT is performed per-block, pass each requested block index
+ * to the emulation function */
while (TotalBlocks--)
ReadBlock(CurrentBlock++);
}