Update BUILD build system module to produce BIN files as well as HEX.
[pub/lufa.git] / Bootloaders / Incomplete / MassStorage / Lib / VirtualFAT.c
index 7b0c5dd..5d91cef 100644 (file)
@@ -34,42 +34,65 @@ static const FATBootBlock_t BootBlock =
        {
                .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())
@@ -78,12 +101,40 @@ static void WriteBlock(uint16_t BlockNumber)
        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)
@@ -95,25 +146,17 @@ static void ReadBlock(uint16_t 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:
@@ -121,6 +164,14 @@ static void ReadBlock(uint16_t BlockNumber)
                        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;
        }
 
@@ -138,6 +189,8 @@ void VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
 {
        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++);
 }
@@ -148,6 +201,8 @@ void VirtualFAT_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
 {
        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++);
 }