From c3e4c9a25c2910d2d66d52215b3406b13d5b23d5 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 29 Jun 2014 12:34:32 +0300 Subject: Add more board models --- boards/dk-tm4c129x/usb_stick_update/simple_fs.c | 865 ++++++++++++++++++++++++ 1 file changed, 865 insertions(+) create mode 100644 boards/dk-tm4c129x/usb_stick_update/simple_fs.c (limited to 'boards/dk-tm4c129x/usb_stick_update/simple_fs.c') diff --git a/boards/dk-tm4c129x/usb_stick_update/simple_fs.c b/boards/dk-tm4c129x/usb_stick_update/simple_fs.c new file mode 100644 index 0000000..2fdc17f --- /dev/null +++ b/boards/dk-tm4c129x/usb_stick_update/simple_fs.c @@ -0,0 +1,865 @@ +//***************************************************************************** +// +// simple_fs.c - Functions for simple FAT file system support +// +// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the DK-TM4C129X Firmware Package. +// +//***************************************************************************** + +#include +#include +#include +#include "simple_fs.h" + +//***************************************************************************** +// +// \addtogroup simple_fs_api +// @{ +// +// This file system API should be used as follows: +// - Initialize it by calling SimpleFsInit(). You must supply a pointer to a +// 512 byte buffer that will be used for storing device sector data. +// - "Open" a file by calling SimpleFsOpen() and passing the 8.3-style filename +// as an 11-character string. +// - Read successive sectors from the file by using the convenience macro +// SimpleFsReadFileSector(). +// +// This API does not use any file handles so there is no way to open more than +// one file at a time. There is also no random access into the file, each +// sector must be read in sequence. +// +// The client of this API supplies a 512-byte buffer for storage of data read +// from the device. But this file also maintains an additional, internal +// 512-byte buffer used for caching FAT sectors. This minimizes the amount +// of device reads required to fetch cluster chain entries from the FAT. +// +// The application code (the client) must also provide a function used for +// reading sectors from the storage device, whatever it may be. This allows +// the code in this file to be independent of the type of device used for +// storing the file system. The name of the function is +// SimpleFsReadMediaSector(). +// +//***************************************************************************** + +//***************************************************************************** +// +// Setup a macro for handling packed data structures. +// +//***************************************************************************** +#if defined(ccs) || \ + defined(codered) || \ + defined(gcc) || \ + defined(rvmdk) || \ + defined(__ARMCC_VERSION) || \ + defined(sourcerygxx) +#define PACKED __attribute__((packed)) +#elif defined(ewarm) +#define PACKED +#else +#error "Unrecognized COMPILER!" +#endif + +//***************************************************************************** +// +// Instruct the IAR compiler to pack the following structures. +// +//***************************************************************************** +#ifdef ewarm +#pragma pack(1) +#endif + +//***************************************************************************** +// +// Structures for mapping FAT file system +// +//***************************************************************************** + +//***************************************************************************** +// +// The FAT16 boot sector extension +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8DriveNumber; + uint8_t ui8Reserved; + uint8_t ui8ExtSig; + uint32_t ui32Serial; + char pcVolumeLabel[11]; + char pcFsType[8]; + uint8_t ui8BootCode[448]; + uint16_t ui16Sig; +} +PACKED tBootExt16; + +//***************************************************************************** +// +// The FAT32 boot sector extension +// +//***************************************************************************** +typedef struct +{ + uint32_t ui32SectorsPerFAT; + uint16_t ui16Flags; + uint16_t ui16Version; + uint32_t ui32RootCluster; + uint16_t ui16InfoSector; + uint16_t ui16BootCopy; + uint8_t ui8Reserved[12]; + uint8_t ui8DriveNumber; + uint8_t ui8Reserved1; + uint8_t ui8ExtSig; + uint32_t ui32Serial; + char pcVolumeLabel[11]; + char pcFsType[8]; + uint8_t ui8BootCode[420]; + uint16_t ui16Sig; +} +PACKED tBootExt32; + +//***************************************************************************** +// +// The FAT16/32 boot sector main section +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8Jump[3]; + uint8_t i8OEMName[8]; + uint16_t ui16BytesPerSector; + uint8_t ui8SectorsPerCluster; + uint16_t ui16ReservedSectors; + uint8_t ui8NumFATs; + uint16_t ui16NumRootEntries; + uint16_t ui16TotalSectorsSmall; + uint8_t ui8MediaDescriptor; + uint16_t ui16SectorsPerFAT; + uint16_t ui16SectorsPerTrack; + uint16_t ui16NumberHeads; + uint32_t ui32HiddenSectors; + uint32_t ui32TotalSectorsBig; + union + { + tBootExt16 sExt16; + tBootExt32 sExt32; + } + PACKED ext; +} +PACKED tBootSector; + +//***************************************************************************** +// +// The partition table +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8Status; + uint8_t ui8CHSFirst[3]; + uint8_t ui8Type; + uint8_t ui8CHSLast[3]; + uint32_t ui32FirstSector; + uint32_t ui32NumBlocks; +} +PACKED tPartitionTable; + +//***************************************************************************** +// +// The master boot record (MBR) +// +//***************************************************************************** +typedef struct +{ + uint8_t ui8CodeArea[440]; + uint8_t ui8DiskSignature[4]; + uint8_t ui8Nulls[2]; + tPartitionTable sPartTable[4]; + uint16_t ui16Sig; +} +PACKED tMasterBootRecord; + +//***************************************************************************** +// +// The structure for a single directory entry +// +//***************************************************************************** +typedef struct +{ + char pcFileName[11]; + uint8_t ui8Attr; + uint8_t ui8Reserved; + uint8_t ui8CreateTime[5]; + uint8_t ui8LastDate[2]; + uint16_t ui16ClusterHi; + uint8_t ui8LastModified[4]; + uint16_t ui16Cluster; + uint32_t ui32FileSize; +} +PACKED tDirEntry; + +//***************************************************************************** +// +// Tell the IAR compiler that the remaining structures do not need to be +// packed. +// +//***************************************************************************** +#ifdef ewarm +#pragma pack() +#endif + +//***************************************************************************** +// +// This structure holds information about the layout of the file system +// +//***************************************************************************** +typedef struct +{ + uint32_t ui32FirstSector; + uint32_t ui32NumBlocks; + uint16_t ui16SectorsPerCluster; + uint16_t ui16MaxRootEntries; + uint32_t ui32SectorsPerFAT; + uint32_t ui32FirstFATSector; + uint32_t ui32LastFATSector; + uint32_t ui32FirstDataSector; + uint32_t ui32Type; + uint32_t ui32StartRootDir; +} +tPartitionInfo; + +static tPartitionInfo sPartInfo; + +//***************************************************************************** +// +// A pointer to the client provided sector buffer. +// +//***************************************************************************** +static uint8_t *g_pui8SectorBuf; + +//***************************************************************************** +// +// Initializes the simple file system +// +// \param pui8SectorBuf is a pointer to a caller supplied 512-byte buffer +// that will be used for holding sectors that are loaded from the media +// storage device. +// +// Reads the MBR, partition table, and boot record to find the logical +// structure of the file system. This function stores the file system +// structural data internally so that the remaining functions of the API +// can read the file system. +// +// To read data from the storage device, the function SimpleFsReadMediaSector() +// will be called. This function is not implemented here but must be +// implemented by the user of this simple file system. +// +// This file system support is extremely simple-minded. It will only +// find the first partition of a FAT16 or FAT32 formatted mass storage +// device. Only very minimal error checking is performed in order to save +// code space. +// +// \return Zero if successful, non-zero if there was an error. +// +//***************************************************************************** +uint32_t +SimpleFsInit(uint8_t *pui8SectorBuf) +{ + tMasterBootRecord *pMBR; + tPartitionTable *pPart; + tBootSector *pBoot; + + // + // Save the sector buffer pointer. The input parameter is assumed + // to be good. + // + g_pui8SectorBuf = pui8SectorBuf; + + // + // Get the MBR + // + if(SimpleFsReadMediaSector(0, pui8SectorBuf)) + { + return(1); + } + + // + // Verify MBR signature - bare minimum validation of MBR. + // + pMBR = (tMasterBootRecord *)pui8SectorBuf; + if(pMBR->ui16Sig != 0xAA55) + { + return(1); + } + + // + // See if this is a MBR or a boot sector. + // + pBoot = (tBootSector *)pui8SectorBuf; + if((strncmp(pBoot->ext.sExt16.pcFsType, "FAT", 3) != 0) && + (strncmp(pBoot->ext.sExt32.pcFsType, "FAT32", 5) != 0)) + { + // + // Get the first partition table + // + pPart = &(pMBR->sPartTable[0]); + + // + // Could optionally check partition type here ... + // + + // + // Get the partition location and size + // + sPartInfo.ui32FirstSector = pPart->ui32FirstSector; + sPartInfo.ui32NumBlocks = pPart->ui32NumBlocks; + + // + // Read the boot sector from the partition + // + if(SimpleFsReadMediaSector(sPartInfo.ui32FirstSector, pui8SectorBuf)) + { + return(1); + } + } + else + { + // + // Extract the number of sectors from the boot sector. + // + sPartInfo.ui32FirstSector = 0; + if(pBoot->ui16TotalSectorsSmall == 0) + { + sPartInfo.ui32NumBlocks = pBoot->ui32TotalSectorsBig; + } + else + { + sPartInfo.ui32NumBlocks = pBoot->ui16TotalSectorsSmall; + } + } + + // + // Get pointer to the boot sector + // + if(pBoot->ext.sExt16.ui16Sig != 0xAA55) + { + return(1); + } + + // + // Verify the sector size is 512. We can't deal with anything else + // + if(pBoot->ui16BytesPerSector != 512) + { + return(1); + } + + // + // Extract some info from the boot record + // + sPartInfo.ui16SectorsPerCluster = pBoot->ui8SectorsPerCluster; + sPartInfo.ui16MaxRootEntries = pBoot->ui16NumRootEntries; + + // + // Decide if we are dealing with FAT16 or FAT32. + // If number of root entries is 0, that suggests FAT32 + // + if(sPartInfo.ui16MaxRootEntries == 0) + { + // + // Confirm FAT 32 signature in the expected place + // + if(!strncmp(pBoot->ext.sExt32.pcFsType, "FAT32 ", 8)) + { + sPartInfo.ui32Type = 32; + } + else + { + return(1); + } + } + // + // Root entries is non-zero, suggests FAT16 + // + else + { + // + // Confirm FAT16 signature + // + if(!strncmp(pBoot->ext.sExt16.pcFsType, "FAT16 ", 8)) + { + sPartInfo.ui32Type = 16; + } + else + { + return(1); + } + } + + // + // Find the beginning of the FAT, in absolute sectors + // + sPartInfo.ui32FirstFATSector = sPartInfo.ui32FirstSector + + pBoot->ui16ReservedSectors; + + // + // Find the end of the FAT in absolute sectors. FAT16 and 32 + // are handled differently. + // + sPartInfo.ui32SectorsPerFAT = (sPartInfo.ui32Type == 16) ? + pBoot->ui16SectorsPerFAT : + pBoot->ext.sExt32.ui32SectorsPerFAT; + sPartInfo.ui32LastFATSector = sPartInfo.ui32FirstFATSector + + sPartInfo.ui32SectorsPerFAT - 1; + + // + // Find the start of the root directory and the data area. + // For FAT16, the root will be stored as an absolute sector number + // For FAT32, the root will be stored as the starting cluster of the root + // The data area start is the absolute first sector of the data area. + // + if(sPartInfo.ui32Type == 16) + { + sPartInfo.ui32StartRootDir = sPartInfo.ui32FirstFATSector + + (sPartInfo.ui32SectorsPerFAT * + pBoot->ui8NumFATs); + sPartInfo.ui32FirstDataSector = sPartInfo.ui32StartRootDir + + (sPartInfo.ui16MaxRootEntries / 16); + } + else + { + sPartInfo.ui32StartRootDir = pBoot->ext.sExt32.ui32RootCluster; + sPartInfo.ui32FirstDataSector = sPartInfo.ui32FirstFATSector + + (sPartInfo.ui32SectorsPerFAT * pBoot->ui8NumFATs); + } + + // + // At this point the file system has been initialized, so return + // success to the caller. + // + return(0); +} + +//***************************************************************************** +// +// Find the next cluster in a FAT chain +// +// \param ui32ThisCluster is the current cluster in the chain +// +// Reads the File Allocation Table (FAT) of the file system to find the +// next cluster in a chain of clusters. The current cluster is passed in +// and the next cluster in the chain will be returned. +// +// This function reads sectors from the storage device as needed in order +// to parse the FAT tables. Error handling is minimal since there is not +// much that can be done if an error is encountered. If any error is +// encountered, or if this is the last cluster in the chain, then 0 is +// returned. This signals the caller to stop traversing the chain (either +// due to error or end of chain). +// +// The function maintains a cache of a single sector from the FAT. It only +// reads in a new FAT sector if the requested cluster is not in the +// currently cached sector. +// +// \return Next cluster number if successful, 0 if this is the last cluster +// or any error is found. +// +//***************************************************************************** +static uint32_t +SimpleFsGetNextCluster(uint_fast32_t ui32ThisCluster) +{ + static uint8_t ui8FATCache[512]; + static uint_fast32_t ui32CachedFATSector = (uint32_t)-1; + uint_fast32_t ui32ClustersPerFATSector; + uint_fast32_t ui32ClusterIdx; + uint_fast32_t ui32FATSector; + uint_fast32_t ui32NextCluster; + uint_fast32_t ui32MaxCluster; + + // + // Compute the maximum possible reasonable cluster number + // + ui32MaxCluster = sPartInfo.ui32NumBlocks / sPartInfo.ui16SectorsPerCluster; + + // + // Make sure cluster input number is reasonable. If not then return + // 0 indicating error. + // + if((ui32ThisCluster < 2) || (ui32ThisCluster > ui32MaxCluster)) + { + return(0); + } + + // + // Compute the index of the requested cluster within the sector. + // Also compute the sector number within the FAT that contains the + // entry for the requested cluster. + // + ui32ClustersPerFATSector = (sPartInfo.ui32Type == 16) ? 256 : 128; + ui32ClusterIdx = ui32ThisCluster % ui32ClustersPerFATSector; + ui32FATSector = ui32ThisCluster / ui32ClustersPerFATSector; + + // + // Check to see if the FAT sector we need is already cached + // + if(ui32FATSector != ui32CachedFATSector) + { + // + // FAT sector we need is not cached, so read it in + // + if(SimpleFsReadMediaSector(sPartInfo.ui32FirstFATSector + ui32FATSector, + ui8FATCache) != 0) + { + // + // There was an error so mark cache as unavailable and return + // an error. + // + ui32CachedFATSector = (uint32_t)-1; + return(0); + } + + // + // Remember which FAT sector was just loaded into the cache. + // + ui32CachedFATSector = ui32FATSector; + } + + // + // Now look up the next cluster value from the cached sector, using this + // requested cluster as an index. It needs to be indexed as 16 or 32 + // bit values depending on whether it is FAT16 or 32 + // If the cluster value means last cluster, then return 0 + // + if(sPartInfo.ui32Type == 16) + { + ui32NextCluster = ((uint16_t *)ui8FATCache)[ui32ClusterIdx]; + if(ui32NextCluster >= 0xFFF8) + { + return(0); + } + } + else + { + ui32NextCluster = ((uint32_t *)ui8FATCache)[ui32ClusterIdx]; + if(ui32NextCluster >= 0x0FFFFFF8) + { + return(0); + } + } + + // + // Check new cluster value to make sure it is reasonable. If not then + // return 0 to indicate an error. + // + if((ui32NextCluster >= 2) && (ui32NextCluster <= ui32MaxCluster)) + { + return(ui32NextCluster); + } + else + { + return(0); + } +} + +//***************************************************************************** +// +// Read a single sector from a file into the sector buffer +// +// \param ui32StartCluster is the first cluster of the file, used to +// initialize the file read. Use 0 for successive sectors. +// +// Reads sectors in sequence from a file and stores the data in the sector +// buffer that was passed in the initial call to SimpleFsInit(). The function +// is initialized with the file to read by passing the starting cluster of +// the file. The function will initialize some static data and return. It +// does not read any file data when passed a starting cluster (and +// returns 0 - this is normal). +// +// Once the function has been initialized with the file's starting cluster, +// then successive calls should be made, passing a value of 0 for the +// cluster number. This tells the function to read the next sector from the +// file and store it in the sector buffer. The function remembers the last +// sector that was read, and each time it is called with a cluster value of +// 0, it will read the next sector. The function will traverse the FAT +// chain as needed to read all the sectors. When a sector has been +// successfully read from a file, the function will return non-zero. When +// there are no more sectors to read, or any error is encountered, the +// function will return 0. +// +// Note that the function always reads a whole sector, even if the end of +// a file does not fill the last sector. It is the responsibility of the +// caller to track the file size and to deal with a partially full last +// sector. +// +// \return Non-zero if a sector was read into the sector buffer, or +// 0 if there are no more sectors or if any error occurred. +// +//***************************************************************************** +uint32_t +SimpleFsGetNextFileSector(uint_fast32_t ui32StartCluster) +{ + static uint_fast32_t ui32WorkingCluster = 0; + static uint_fast32_t ui32WorkingSector; + uint_fast32_t ui32ReadSector; + + // + // If user specified starting cluster, then init the working cluster + // and sector values + // + if(ui32StartCluster) + { + ui32WorkingCluster = ui32StartCluster; + ui32WorkingSector = 0; + return(0); + } + + // + // Otherwise, make sure there is a valid working cluster already + // + else if(ui32WorkingCluster == 0) + { + return(0); + } + + // + // If the current working sector is the same as sectors per cluster, + // then that means that the next cluster needs to be loaded. + // + if(ui32WorkingSector == sPartInfo.ui16SectorsPerCluster) + { + // + // Get the next cluster in the chain for this file. + // + ui32WorkingCluster = SimpleFsGetNextCluster(ui32WorkingCluster); + + // + // If the next cluster is valid, then reset the working sector + // + if(ui32WorkingCluster) + { + ui32WorkingSector = 0; + } + + // + // Next cluster is not valid, or this was the end of the chain. + // Clear the working cluster and return an indication that no new + // sector data was loaded. + // + else + { + ui32WorkingCluster = 0; + return(0); + } + } + + // + // Calculate the sector to read from. It is the sector of the start + // of the working cluster, plus the working sector (the sector within + // the cluster), plus the offset to the start of the data area. + // Note that the cluster needs to be reduced by 2 in order to index + // properly into the data area. That is a feature of FAT file system. + // + ui32ReadSector = (ui32WorkingCluster - 2) * sPartInfo.ui16SectorsPerCluster; + ui32ReadSector += ui32WorkingSector; + ui32ReadSector += sPartInfo.ui32FirstDataSector; + + // + // Attempt to read the next sector from the cluster. If not successful, + // then clear the working cluster and return a non-success indication. + // + if(SimpleFsReadMediaSector(ui32ReadSector, g_pui8SectorBuf) != 0) + { + ui32WorkingCluster = 0; + return(0); + } + else + { + // + // Read was successful. Increment to the next sector of the cluster + // and return a success indication. + // + ui32WorkingSector++; + return(1); + } +} + +//***************************************************************************** +// +// Find a file in the root directory of the file system and open it for +// reading. +// +// \param pcName83 is an 11-character string that represents the 8.3 file +// name of the file to open. +// +// This function traverses the root directory of the file system to find +// the file name specified by the caller. Note that the file name must be +// an 8.3 file name that is 11 characters int32_t. The first 8 characters are +// the base name and the last 3 characters are the extension. If there are +// fewer characters in the base name or extension, the name should be padded +// with spaces. For example "myfile.bn" has fewer than 11 characters, and +// should be passed with padding like this: "myfile bn ". Note the extra +// spaces, and that the dot ('.') is not part of the string that is passed +// to this function. +// +// If the file is found, then it initializes the file for reading, and returns +// the file length. The file can be read by making successive calls to +// SimpleFsReadFileSector(). +// +// The function only searches the root directory and ignores any +// subdirectories. It also ignores any int32_t file name entries, looking only +// at the 8.3 file name for a match. +// +// \return The size of the file if it is found, or 0 if the file could not +// be found. +// +//***************************************************************************** +uint32_t +SimpleFsOpen(char *pcName83) +{ + tDirEntry *pDirEntry; + uint_fast32_t ui32DirSector; + uint_fast32_t ui32FirstCluster; + + // + // Find starting root dir sector, only used for FAT16 + // If FAT32 then this is the first cluster of root dir + // + ui32DirSector = sPartInfo.ui32StartRootDir; + + // + // For FAT32, root dir is like a file, so init a file read of the root dir + // + if(sPartInfo.ui32Type == 32) + { + SimpleFsGetNextFileSector(ui32DirSector); + } + + // + // Search the root directory entry for the firmware file + // + while(1) + { + // + // Read in a directory block. + // + if(sPartInfo.ui32Type == 16) + { + // + // For FAT16, read in a sector of the root directory + // + if(SimpleFsReadMediaSector(ui32DirSector, g_pui8SectorBuf)) + { + return(0); + } + } + else + { + // + // For FAT32, the root directory is treated like a file. + // The root directory sector will be loaded into the sector buf + // + if(SimpleFsGetNextFileSector(0) == 0) + { + return(0); + } + } + + // + // Initialize the directory entry pointer to the first entry of + // this sector. + // + pDirEntry = (tDirEntry *)g_pui8SectorBuf; + + // + // Iterate through all the directory entries in this sector + // + while((uint8_t *)pDirEntry < &g_pui8SectorBuf[512]) + { + // + // If the 8.3 filename of this entry matches the firmware + // file name, then we have a match, so return a pointer to + // this entry. + // + if(!strncmp(pDirEntry->pcFileName, pcName83, 11)) + { + // + // Compute the starting cluster of the file + // + ui32FirstCluster = pDirEntry->ui16Cluster; + if(sPartInfo.ui32Type == 32) + { + // + // For FAT32, add in the upper word of the + // starting cluster number + // + ui32FirstCluster += pDirEntry->ui16ClusterHi << 16; + } + + // + // Initialize the start of the file + // + SimpleFsGetNextFileSector(ui32FirstCluster); + return(pDirEntry->ui32FileSize); + } + + // + // Advance to the next entry in this sector. + // + pDirEntry++; + } + + // + // Need to get the next sector in the directory. Handled + // differently depending on if this is FAT16 or 32 + // + if(sPartInfo.ui32Type == 16) + { + // + // FAT16: advance sectors as int32_t as there are more possible + // entries. + // + sPartInfo.ui16MaxRootEntries -= 512 / 32; + if(sPartInfo.ui16MaxRootEntries) + { + ui32DirSector++; + } + else + { + // + // Ran out of directory entries and didn't find the file, + // so return a null. + // + return(0); + } + } + else + { + // + // FAT32: there is nothing to compute here. The next root + // dir sector will be fetched at the top of the loop + // + } + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +// @} +// +//***************************************************************************** -- cgit v1.3.1