aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDean Camera <dean@fourwalledcubicle.com>2013-03-29 10:23:09 +0000
committerDean Camera <dean@fourwalledcubicle.com>2013-03-29 10:23:09 +0000
commit83d5c4729e3cb014d2f75a5ac4132658ad6b7ea8 (patch)
treef03feebdd7163814ef7ed3cbeb3a7643cf105567
parent148b434228cfa94160cc1dbfafc455fd86825fa1 (diff)
downloadlufa-83d5c4729e3cb014d2f75a5ac4132658ad6b7ea8.tar.gz
lufa-83d5c4729e3cb014d2f75a5ac4132658ad6b7ea8.tar.bz2
lufa-83d5c4729e3cb014d2f75a5ac4132658ad6b7ea8.zip
Update Mass Storage bootloader for Linux compatibility, and to reduce the compiled bootloader size. Linux appears to replace files with a cluster offset on the disk rather than re-using the same disk clusters (unlike Windows) so the file offset needs to be tracked and compensated for.
-rw-r--r--Bootloaders/MassStorage/Lib/SCSI.c13
-rw-r--r--Bootloaders/MassStorage/Lib/VirtualFAT.c181
-rw-r--r--Bootloaders/MassStorage/Lib/VirtualFAT.h29
3 files changed, 131 insertions, 92 deletions
diff --git a/Bootloaders/MassStorage/Lib/SCSI.c b/Bootloaders/MassStorage/Lib/SCSI.c
index ea0700a27..b23a5a07b 100644
--- a/Bootloaders/MassStorage/Lib/SCSI.c
+++ b/Bootloaders/MassStorage/Lib/SCSI.c
@@ -255,10 +255,15 @@ static bool SCSI_Command_ReadWrite_10(USB_ClassInfo_MS_Device_t* const MSInterfa
}
/* Determine if the packet is a READ (10) or WRITE (10) command, call appropriate function */
- if (IsDataRead == DATA_READ)
- VirtualFAT_ReadBlocks(BlockAddress, TotalBlocks);
- else
- VirtualFAT_WriteBlocks(BlockAddress, TotalBlocks);
+ while (TotalBlocks--)
+ {
+ if (IsDataRead == DATA_READ)
+ VirtualFAT_ReadBlock(BlockAddress);
+ else
+ VirtualFAT_WriteBlock(BlockAddress);
+
+ BlockAddress++;
+ }
/* Update the bytes transferred counter and succeed the command */
MSInterfaceInfo->State.CommandBlock.DataTransferLength -= ((uint32_t)TotalBlocks * SECTOR_SIZE_BYTES);
diff --git a/Bootloaders/MassStorage/Lib/VirtualFAT.c b/Bootloaders/MassStorage/Lib/VirtualFAT.c
index 2e90a8101..e50014be8 100644
--- a/Bootloaders/MassStorage/Lib/VirtualFAT.c
+++ b/Bootloaders/MassStorage/Lib/VirtualFAT.c
@@ -72,12 +72,13 @@ static const FATBootBlock_t BootBlock =
};
/** FAT 8.3 style directory entry, for the virtual FLASH contents file. */
-static FATDirectoryEntry_t FirmwareFileEntries[] =
+FATDirectoryEntry_t FirmwareFileEntries[] =
{
/* Root volume label entry; disk label is contained in the Filename and
* Extension fields (concatenated) with a special attribute flag - other
* fields are ignored. Should be the same as the label in the boot block.
*/
+ [DISK_FILE_ENTRY_VolumeID] =
{
.MSDOS_Directory =
{
@@ -94,6 +95,7 @@ static FATDirectoryEntry_t FirmwareFileEntries[] =
/* VFAT Long File Name entry for the virtual firmware file; required to
* prevent corruption from systems that are unable to detect the device
* as being a legacy MSDOS style FAT12 volume. */
+ [DISK_FILE_ENTRY_FirmwareLFN] =
{
.VFAT_LongFileName =
{
@@ -121,6 +123,7 @@ static FATDirectoryEntry_t FirmwareFileEntries[] =
},
/* MSDOS file entry for the virtual Firmware image. */
+ [DISK_FILE_ENTRY_FirmwareMSDOS] =
{
.MSDOS_File =
{
@@ -136,6 +139,12 @@ static FATDirectoryEntry_t FirmwareFileEntries[] =
},
};
+/** Starting block of the virtual firmware file image on disk. On Windows, files
+ * are (usually?) replaced using the original file's physical sectors. On Linux
+ * file replacements are performed with an offset.
+ */
+uint16_t FileStartBlock = DISK_BLOCK_DataStartBlock;
+
/** 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
@@ -170,70 +179,118 @@ static void UpdateFAT12ClusterEntry(uint8_t* const FATTable,
}
}
-/** Writes a block of data to the virtual FAT filesystem, from the USB Mass
- * Storage interface.
+/** 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
+ * firmware file's sector ranges in the emulated FAT file system.
*
- * \param[in] BlockNumber Index of the block to write.
+ * \param[in] BlockNumber Physical disk block to read from
+ * \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 WriteVirtualBlock(const uint16_t BlockNumber)
+static void ReadWriteFirmwareFileBlock(const uint16_t BlockNumber,
+ uint8_t* BlockBuffer,
+ const bool Read)
{
- uint8_t BlockBuffer[SECTOR_SIZE_BYTES];
-
- /* Buffer the entire block to be written from the host */
- Endpoint_Read_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
- Endpoint_ClearOUT();
-
- if ((BlockNumber >= 4) && (BlockNumber < (4 + FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES))))
+ /* Range check the write request - abort if requested block is not within the
+ * virtual firmware file sector range */
+ if (!((BlockNumber >= FileStartBlock) && (BlockNumber < (FileStartBlock + FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES)))))
+ 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)
{
- #if (FLASHEND > 0xFFFF)
- uint32_t WriteFlashAddress = (uint32_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
- #else
- uint16_t WriteFlashAddress = (uint16_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
- #endif
-
+ /* Read out the mapped block of data from the device's FLASH */
+ 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
+ {
+ /* Write out the mapped block of data to the device's FLASH */
for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i += 2)
{
- if ((WriteFlashAddress % SPM_PAGESIZE) == 0)
+ if ((FlashAddress % SPM_PAGESIZE) == 0)
{
/* Erase the given FLASH page, ready to be programmed */
- BootloaderAPI_ErasePage(WriteFlashAddress);
+ BootloaderAPI_ErasePage(FlashAddress);
}
/* Write the next data word to the FLASH page */
- BootloaderAPI_FillWord(WriteFlashAddress, (BlockBuffer[i + 1] << 8) | BlockBuffer[i]);
- WriteFlashAddress += 2;
+ BootloaderAPI_FillWord(FlashAddress, (BlockBuffer[i + 1] << 8) | BlockBuffer[i]);
+ FlashAddress += 2;
- if ((WriteFlashAddress % SPM_PAGESIZE) == 0)
+ if ((FlashAddress % SPM_PAGESIZE) == 0)
{
/* Write the filled FLASH page to memory */
- BootloaderAPI_WritePage(WriteFlashAddress - SPM_PAGESIZE);
+ BootloaderAPI_WritePage(FlashAddress - SPM_PAGESIZE);
}
}
}
}
+/** Writes a block of data to the virtual FAT filesystem, from the USB Mass
+ * Storage interface.
+ *
+ * \param[in] BlockNumber Index of the block to write.
+ */
+void VirtualFAT_WriteBlock(const uint16_t BlockNumber)
+{
+ uint8_t BlockBuffer[SECTOR_SIZE_BYTES];
+
+ /* Buffer the entire block to be written from the host */
+ Endpoint_Read_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
+ Endpoint_ClearOUT();
+
+ if (BlockNumber == DISK_BLOCK_RootFilesBlock)
+ {
+ /* Copy over the updated directory entries */
+ memcpy(FirmwareFileEntries, BlockBuffer, sizeof(FirmwareFileEntries));
+
+ /* Save the new firmware file block offset so the written and read file
+ * contents can be correctly mapped to the device's FLASH pages */
+ FileStartBlock = DISK_BLOCK_DataStartBlock +
+ (FirmwareFileEntries[DISK_FILE_ENTRY_FirmwareMSDOS].MSDOS_File.StartingCluster - 2) * SECTOR_PER_CLUSTER;
+ }
+ else
+ {
+ ReadWriteFirmwareFileBlock(BlockNumber, BlockBuffer, false);
+ }
+}
+
/** Reads a block of data from the virtual FAT filesystem, and sends it to the
* host via the USB Mass Storage interface.
*
* \param[in] BlockNumber Index of the block to read.
*/
-static void ReadVirtualBlock(const uint16_t BlockNumber)
+void VirtualFAT_ReadBlock(const uint16_t BlockNumber)
{
uint8_t BlockBuffer[SECTOR_SIZE_BYTES];
memset(BlockBuffer, 0x00, sizeof(BlockBuffer));
switch (BlockNumber)
{
- case 0: /* Block 0: Boot block sector */
+ case DISK_BLOCK_BootBlock:
memcpy(BlockBuffer, &BootBlock, sizeof(FATBootBlock_t));
/* Add the magic signature to the end of the block */
BlockBuffer[SECTOR_SIZE_BYTES - 2] = 0x55;
BlockBuffer[SECTOR_SIZE_BYTES - 1] = 0xAA;
+
break;
- case 1: /* Block 1: First FAT12 cluster chain copy */
- case 2: /* Block 2: Second FAT12 cluster chain copy */
+ case DISK_BLOCK_FATBlock1:
+ case DISK_BLOCK_FATBlock2:
/* Cluster 0: Media type/Reserved */
UpdateFAT12ClusterEntry(BlockBuffer, 0, 0xF00 | BootBlock.MediaDescriptor);
@@ -241,32 +298,27 @@ static void ReadVirtualBlock(const uint16_t BlockNumber)
UpdateFAT12ClusterEntry(BlockBuffer, 1, 0xFFF);
/* Cluster 2 onwards: Cluster chain of FIRMWARE.BIN */
- for (uint16_t i = 0; i < FILE_CLUSTERS(FIRMWARE_FILE_SIZE_BYTES); i++)
- UpdateFAT12ClusterEntry(BlockBuffer, i+2, i+3);
+ for (uint16_t i = 0; i <= FILE_CLUSTERS(FIRMWARE_FILE_SIZE_BYTES); i++)
+ {
+ uint16_t CurrentCluster = FirmwareFileEntries[DISK_FILE_ENTRY_FirmwareMSDOS].MSDOS_File.StartingCluster + 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);
+ }
- /* Mark last cluster as end of file */
- UpdateFAT12ClusterEntry(BlockBuffer, FILE_CLUSTERS(FIRMWARE_FILE_SIZE_BYTES) + 1, 0xFFF);
break;
- case 3: /* Block 3: Root file entries */
+ case DISK_BLOCK_RootFilesBlock:
memcpy(BlockBuffer, FirmwareFileEntries, sizeof(FirmwareFileEntries));
+
break;
default: /* Blocks 4 onwards: Data allocation section */
- if ((BlockNumber >= 4) && (BlockNumber < (4 + FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES))))
- {
- #if (FLASHEND > 0xFFFF)
- 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++);
- #else
- uint16_t ReadFlashAddress = (uint16_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
-
- for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
- BlockBuffer[i] = pgm_read_byte(ReadFlashAddress++);
- #endif
- }
+ ReadWriteFirmwareFileBlock(BlockNumber, BlockBuffer, true);
break;
}
@@ -275,38 +327,3 @@ static void ReadVirtualBlock(const uint16_t BlockNumber)
Endpoint_Write_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
Endpoint_ClearIN();
}
-
-/** Writes a number of blocks to the virtual FAT file system, from the host
- * PC via the USB Mass Storage interface.
- *
- * \param[in] BlockAddress Data block starting address for the write sequence
- * \param[in] TotalBlocks Number of blocks of data to write
- */
-void VirtualFAT_WriteBlocks(const uint16_t BlockAddress,
- uint16_t TotalBlocks)
-{
- uint16_t CurrentBlock = (uint16_t)BlockAddress;
-
- /* Emulated FAT is performed per-block, pass each requested block index
- * to the emulated FAT block write function */
- while (TotalBlocks--)
- WriteVirtualBlock(CurrentBlock++);
-}
-
-/** Reads a number of blocks from the virtual FAT file system, and sends them
- * to the host PC via the USB Mass Storage interface.
- *
- * \param[in] BlockAddress Data block starting address for the read sequence
- * \param[in] TotalBlocks Number of blocks of data to read
- */
-void VirtualFAT_ReadBlocks(const uint16_t BlockAddress,
- uint16_t TotalBlocks)
-{
- uint16_t CurrentBlock = (uint16_t)BlockAddress;
-
- /* Emulated FAT is performed per-block, pass each requested block index
- * to the emulated FAT block read function */
- while (TotalBlocks--)
- ReadVirtualBlock(CurrentBlock++);
-}
-
diff --git a/Bootloaders/MassStorage/Lib/VirtualFAT.h b/Bootloaders/MassStorage/Lib/VirtualFAT.h
index 37095eae5..820fe54d5 100644
--- a/Bootloaders/MassStorage/Lib/VirtualFAT.h
+++ b/Bootloaders/MassStorage/Lib/VirtualFAT.h
@@ -121,6 +121,23 @@
#define FAT_ORDINAL_LAST_ENTRY (1 << 6)
//@}
+ /* Enums: */
+ enum
+ {
+ DISK_FILE_ENTRY_VolumeID = 0,
+ DISK_FILE_ENTRY_FirmwareLFN = 1,
+ DISK_FILE_ENTRY_FirmwareMSDOS = 2,
+ };
+
+ enum
+ {
+ DISK_BLOCK_BootBlock = 0,
+ DISK_BLOCK_FATBlock1 = 1,
+ DISK_BLOCK_FATBlock2 = 2,
+ DISK_BLOCK_RootFilesBlock = 3,
+ DISK_BLOCK_DataStartBlock = 4,
+ };
+
/* Type Definitions: */
/** FAT boot block structure definition, used to identify the core
* parameters of a FAT filesystem stored on a disk.
@@ -213,13 +230,13 @@
static void UpdateFAT12ClusterEntry(uint8_t* const FATTable,
const uint16_t Index,
const uint16_t ChainEntry) AUX_BOOT_SECTION;
- static void WriteVirtualBlock(const uint16_t BlockNumber) AUX_BOOT_SECTION;
- static void ReadVirtualBlock(const uint16_t BlockNumber) AUX_BOOT_SECTION;
+
+ static void ReadWriteFirmwareFileBlock(const uint16_t BlockNumber,
+ uint8_t* BlockBuffer,
+ const bool Read) AUX_BOOT_SECTION;
#endif
- void VirtualFAT_WriteBlocks(const uint16_t BlockAddress,
- uint16_t TotalBlocks) AUX_BOOT_SECTION;
+ void VirtualFAT_WriteBlock(const uint16_t BlockNumber) AUX_BOOT_SECTION;
+ void VirtualFAT_ReadBlock(const uint16_t BlockNumber) AUX_BOOT_SECTION;
- void VirtualFAT_ReadBlocks(const uint16_t BlockAddress,
- uint16_t TotalBlocks) AUX_BOOT_SECTION;
#endif