41c661ed398d240a54a1b8f7cf7d6a8d9928af7f
[pub/USBasp.git] / Bootloaders / MassStorage / Lib / VirtualFAT.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2013.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2013 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaims all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 /** \file
32 *
33 * Virtualized FAT12 filesystem implementation, to perform self-programming
34 * in response to read and write requests to the virtual filesystem by the
35 * host PC.
36 */
37
38 #define INCLUDE_FROM_VIRTUAL_FAT_C
39 #include "VirtualFAT.h"
40
41 /** FAT filesystem boot sector block, must be the first sector on the physical
42 * disk so that the host can identify the presence of a FAT filesystem. This
43 * block is truncated; normally a large bootstrap section is located near the
44 * end of the block for booting purposes however as this is not meant to be a
45 * bootable disk it is omitted for space reasons.
46 *
47 * \note When returning the boot block to the host, the magic signature 0xAA55
48 * must be added to the very end of the block to identify it as a boot
49 * block.
50 */
51 static const FATBootBlock_t BootBlock =
52 {
53 .Bootstrap = {0xEB, 0x3C, 0x90},
54 .Description = "mkdosfs",
55 .SectorSize = SECTOR_SIZE_BYTES,
56 .SectorsPerCluster = SECTOR_PER_CLUSTER,
57 .ReservedSectors = 1,
58 .FATCopies = 2,
59 .RootDirectoryEntries = (SECTOR_SIZE_BYTES / sizeof(FATDirectoryEntry_t)),
60 .TotalSectors16 = LUN_MEDIA_BLOCKS,
61 .MediaDescriptor = 0xF8,
62 .SectorsPerFAT = 1,
63 .SectorsPerTrack = (LUN_MEDIA_BLOCKS % 64),
64 .Heads = (LUN_MEDIA_BLOCKS / 64),
65 .HiddenSectors = 0,
66 .TotalSectors32 = 0,
67 .PhysicalDriveNum = 0,
68 .ExtendedBootRecordSig = 0x29,
69 .VolumeSerialNumber = 0x12345678,
70 .VolumeLabel = "LUFA BOOT ",
71 .FilesystemIdentifier = "FAT12 ",
72 };
73
74 /** FAT 8.3 style directory entry, for the virtual FLASH contents file. */
75 static FATDirectoryEntry_t FirmwareFileEntries[2] =
76 {
77 /* Root volume label entry; disk label is contained in the Filename and
78 * Extension fields (concatenated) with a special attribute flag - other
79 * fields are ignored. Should be the same as the label in the boot block.
80 */
81 {
82 .Filename = "LUFA BOO",
83 .Extension = "T ",
84 .Attributes = (1 << 3),
85 .Reserved = {0},
86 .CreationTime = 0,
87 .CreationDate = 0,
88 .StartingCluster = 0,
89 .FileSizeBytes = 0,
90 },
91
92 /* File entry for the virtual Firmware image. */
93 {
94 .Filename = "FIRMWARE",
95 .Extension = "BIN",
96 .Attributes = 0,
97 .Reserved = {0},
98 .CreationTime = FAT_TIME(1, 1, 0),
99 .CreationDate = FAT_DATE(14, 2, 1989),
100 .StartingCluster = 2,
101 .FileSizeBytes = FIRMWARE_FILE_SIZE_BYTES,
102 },
103 };
104
105
106 /** Updates a FAT12 cluster entry in the FAT file table with the specified next
107 * chain index. If the cluster is the last in the file chain, the magic value
108 * 0xFFF is used.
109 *
110 * \note FAT data cluster indexes are offset by 2, so that cluster 2 is the
111 * first file data cluster on the disk. See the FAT specification.
112 *
113 * \param[out] FATTable Pointer to the FAT12 allocation table
114 * \param[in] Index Index of the cluster entry to update
115 * \param[in] ChainEntry Next cluster index in the file chain
116 */
117 static void UpdateFAT12ClusterEntry(uint8_t* const FATTable,
118 const uint16_t Index,
119 const uint16_t ChainEntry)
120 {
121 /* Calculate the starting offset of the cluster entry in the FAT12 table */
122 uint8_t FATOffset = (Index + (Index >> 1));
123 bool UpperNibble = ((Index & 1) != 0);
124
125 /* Check if the start of the entry is at an upper nibble of the byte, fill
126 * out FAT12 entry as required */
127 if (UpperNibble)
128 {
129 FATTable[FATOffset] = (FATTable[FATOffset] & 0x0F) | ((ChainEntry & 0x0F) << 4);
130 FATTable[FATOffset + 1] = (ChainEntry >> 4);
131 }
132 else
133 {
134 FATTable[FATOffset] = ChainEntry;
135 FATTable[FATOffset + 1] = (FATTable[FATOffset] & 0xF0) | (ChainEntry >> 8);
136 }
137 }
138
139 /** Writes a block of data to the virtual FAT filesystem, from the USB Mass
140 * Storage interface.
141 *
142 * \param[in] BlockNumber Index of the block to write.
143 */
144 static void WriteVirtualBlock(const uint16_t BlockNumber)
145 {
146 uint8_t BlockBuffer[SECTOR_SIZE_BYTES];
147
148 /* Buffer the entire block to be written from the host */
149 Endpoint_Read_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
150 Endpoint_ClearOUT();
151
152 if ((BlockNumber >= 4) && (BlockNumber < (4 + FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES))))
153 {
154 #if (FLASHEND > 0xFFFF)
155 uint32_t WriteFlashAddress = (uint32_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
156 #else
157 uint16_t WriteFlashAddress = (uint16_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
158 #endif
159
160 for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i += 2)
161 {
162 if ((WriteFlashAddress % SPM_PAGESIZE) == 0)
163 {
164 /* Erase the given FLASH page, ready to be programmed */
165 BootloaderAPI_ErasePage(WriteFlashAddress);
166 }
167
168 /* Write the next data word to the FLASH page */
169 BootloaderAPI_FillWord(WriteFlashAddress, (BlockBuffer[i + 1] << 8) | BlockBuffer[i]);
170 WriteFlashAddress += 2;
171
172 if ((WriteFlashAddress % SPM_PAGESIZE) == 0)
173 {
174 /* Write the filled FLASH page to memory */
175 BootloaderAPI_WritePage(WriteFlashAddress - SPM_PAGESIZE);
176 }
177 }
178 }
179 }
180
181 /** Reads a block of data from the virtual FAT filesystem, and sends it to the
182 * host via the USB Mass Storage interface.
183 *
184 * \param[in] BlockNumber Index of the block to read.
185 */
186 static void ReadVirtualBlock(const uint16_t BlockNumber)
187 {
188 uint8_t BlockBuffer[SECTOR_SIZE_BYTES];
189 memset(BlockBuffer, 0x00, sizeof(BlockBuffer));
190
191 switch (BlockNumber)
192 {
193 case 0: /* Block 0: Boot block sector */
194 memcpy(BlockBuffer, &BootBlock, sizeof(FATBootBlock_t));
195
196 /* Add the magic signature to the end of the block */
197 BlockBuffer[SECTOR_SIZE_BYTES - 2] = 0x55;
198 BlockBuffer[SECTOR_SIZE_BYTES - 1] = 0xAA;
199 break;
200
201 case 1: /* Block 1: First FAT12 cluster chain copy */
202 case 2: /* Block 2: Second FAT12 cluster chain copy */
203 /* Cluster 0: Media type/Reserved */
204 UpdateFAT12ClusterEntry(BlockBuffer, 0, 0xF00 | BootBlock.MediaDescriptor);
205
206 /* Cluster 1: Reserved */
207 UpdateFAT12ClusterEntry(BlockBuffer, 1, 0xFFF);
208
209 /* Cluster 2 onwards: Cluster chain of FIRMWARE.BIN */
210 for (uint16_t i = 0; i < FILE_CLUSTERS(FIRMWARE_FILE_SIZE_BYTES); i++)
211 UpdateFAT12ClusterEntry(BlockBuffer, i+2, i+3);
212
213 /* Mark last cluster as end of file */
214 UpdateFAT12ClusterEntry(BlockBuffer, FILE_CLUSTERS(FIRMWARE_FILE_SIZE_BYTES) + 1, 0xFFF);
215 break;
216
217 case 3: /* Block 3: Root file entries */
218 memcpy(BlockBuffer, FirmwareFileEntries, sizeof(FirmwareFileEntries));
219 break;
220
221 default: /* Blocks 4 onwards: Data allocation section */
222 if ((BlockNumber >= 4) && (BlockNumber < (4 + FILE_SECTORS(FIRMWARE_FILE_SIZE_BYTES))))
223 {
224 #if (FLASHEND > 0xFFFF)
225 uint32_t ReadFlashAddress = (uint32_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
226
227 for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
228 BlockBuffer[i] = pgm_read_byte_far(ReadFlashAddress++);
229 #else
230 uint16_t ReadFlashAddress = (uint16_t)(BlockNumber - 4) * SECTOR_SIZE_BYTES;
231
232 for (uint16_t i = 0; i < SECTOR_SIZE_BYTES; i++)
233 BlockBuffer[i] = pgm_read_byte(ReadFlashAddress++);
234 #endif
235 }
236
237 break;
238 }
239
240 /* Write the entire read block Buffer to the host */
241 Endpoint_Write_Stream_LE(BlockBuffer, sizeof(BlockBuffer), NULL);
242 Endpoint_ClearIN();
243 }
244
245 /** Writes a number of blocks to the virtual FAT file system, from the host
246 * PC via the USB Mass Storage interface.
247 *
248 * \param[in] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
249 * \param[in] BlockAddress Data block starting address for the write sequence
250 * \param[in] TotalBlocks Number of blocks of data to write
251 */
252 void VirtualFAT_WriteBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
253 const uint32_t BlockAddress,
254 uint16_t TotalBlocks)
255 {
256 uint16_t CurrentBlock = (uint16_t)BlockAddress;
257
258 /* Emulated FAT is performed per-block, pass each requested block index
259 * to the emulated FAT block write function */
260 while (TotalBlocks--)
261 WriteVirtualBlock(CurrentBlock++);
262 }
263
264 /** Reads a number of blocks from the virtual FAT file system, and sends them
265 * to the host PC via the USB Mass Storage interface.
266 *
267 * \param[in] MSInterfaceInfo Pointer to a structure containing a Mass Storage Class configuration and state
268 * \param[in] BlockAddress Data block starting address for the read sequence
269 * \param[in] TotalBlocks Number of blocks of data to read
270 */
271 void VirtualFAT_ReadBlocks(USB_ClassInfo_MS_Device_t* const MSInterfaceInfo,
272 const uint32_t BlockAddress,
273 uint16_t TotalBlocks)
274 {
275 uint16_t CurrentBlock = (uint16_t)BlockAddress;
276
277 /* Emulated FAT is performed per-block, pass each requested block index
278 * to the emulated FAT block read function */
279 while (TotalBlocks--)
280 ReadVirtualBlock(CurrentBlock++);
281 }
282