D:/DRISSI/arduino-0022/arduino-0022/libraries/SD/utility/SdVolume.cpp
00001 /* Arduino SdFat Library
00002  * Copyright (C) 2009 by William Greiman
00003  *
00004  * This file is part of the Arduino SdFat Library
00005  *
00006  * This Library is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This Library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with the Arduino SdFat Library.  If not, see
00018  * <http://www.gnu.org/licenses/>.
00019  */
00020 #include <SdFat.h>
00021 //------------------------------------------------------------------------------
00022 // raw block cache
00023 // init cacheBlockNumber_to invalid SD block number
00024 uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
00025 cache_t  SdVolume::cacheBuffer_;     // 512 byte cache for Sd2Card
00026 Sd2Card* SdVolume::sdCard_;          // pointer to SD card object
00027 uint8_t  SdVolume::cacheDirty_ = 0;  // cacheFlush() will write block if true
00028 uint32_t SdVolume::cacheMirrorBlock_ = 0;  // mirror  block for second FAT
00029 //------------------------------------------------------------------------------
00030 // find a contiguous group of clusters
00031 uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
00032   // start of group
00033   uint32_t bgnCluster;
00034 
00035   // flag to save place to start next search
00036   uint8_t setStart;
00037 
00038   // set search start cluster
00039   if (*curCluster) {
00040     // try to make file contiguous
00041     bgnCluster = *curCluster + 1;
00042 
00043     // don't save new start location
00044     setStart = false;
00045   } else {
00046     // start at likely place for free cluster
00047     bgnCluster = allocSearchStart_;
00048 
00049     // save next search start if one cluster
00050     setStart = 1 == count;
00051   }
00052   // end of group
00053   uint32_t endCluster = bgnCluster;
00054 
00055   // last cluster of FAT
00056   uint32_t fatEnd = clusterCount_ + 1;
00057 
00058   // search the FAT for free clusters
00059   for (uint32_t n = 0;; n++, endCluster++) {
00060     // can't find space checked all clusters
00061     if (n >= clusterCount_) return false;
00062 
00063     // past end - start from beginning of FAT
00064     if (endCluster > fatEnd) {
00065       bgnCluster = endCluster = 2;
00066     }
00067     uint32_t f;
00068     if (!fatGet(endCluster, &f)) return false;
00069 
00070     if (f != 0) {
00071       // cluster in use try next cluster as bgnCluster
00072       bgnCluster = endCluster + 1;
00073     } else if ((endCluster - bgnCluster + 1) == count) {
00074       // done - found space
00075       break;
00076     }
00077   }
00078   // mark end of chain
00079   if (!fatPutEOC(endCluster)) return false;
00080 
00081   // link clusters
00082   while (endCluster > bgnCluster) {
00083     if (!fatPut(endCluster - 1, endCluster)) return false;
00084     endCluster--;
00085   }
00086   if (*curCluster != 0) {
00087     // connect chains
00088     if (!fatPut(*curCluster, bgnCluster)) return false;
00089   }
00090   // return first cluster number to caller
00091   *curCluster = bgnCluster;
00092 
00093   // remember possible next free cluster
00094   if (setStart) allocSearchStart_ = bgnCluster + 1;
00095 
00096   return true;
00097 }
00098 //------------------------------------------------------------------------------
00099 uint8_t SdVolume::cacheFlush(void) {
00100   if (cacheDirty_) {
00101     if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
00102       return false;
00103     }
00104     // mirror FAT tables
00105     if (cacheMirrorBlock_) {
00106       if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
00107         return false;
00108       }
00109       cacheMirrorBlock_ = 0;
00110     }
00111     cacheDirty_ = 0;
00112   }
00113   return true;
00114 }
00115 //------------------------------------------------------------------------------
00116 uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) {
00117   if (cacheBlockNumber_ != blockNumber) {
00118     if (!cacheFlush()) return false;
00119     if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false;
00120     cacheBlockNumber_ = blockNumber;
00121   }
00122   cacheDirty_ |= action;
00123   return true;
00124 }
00125 //------------------------------------------------------------------------------
00126 // cache a zero block for blockNumber
00127 uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) {
00128   if (!cacheFlush()) return false;
00129 
00130   // loop take less flash than memset(cacheBuffer_.data, 0, 512);
00131   for (uint16_t i = 0; i < 512; i++) {
00132     cacheBuffer_.data[i] = 0;
00133   }
00134   cacheBlockNumber_ = blockNumber;
00135   cacheSetDirty();
00136   return true;
00137 }
00138 //------------------------------------------------------------------------------
00139 // return the size in bytes of a cluster chain
00140 uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const {
00141   uint32_t s = 0;
00142   do {
00143     if (!fatGet(cluster, &cluster)) return false;
00144     s += 512UL << clusterSizeShift_;
00145   } while (!isEOC(cluster));
00146   *size = s;
00147   return true;
00148 }
00149 //------------------------------------------------------------------------------
00150 // Fetch a FAT entry
00151 uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const {
00152   if (cluster > (clusterCount_ + 1)) return false;
00153   uint32_t lba = fatStartBlock_;
00154   lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
00155   if (lba != cacheBlockNumber_) {
00156     if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
00157   }
00158   if (fatType_ == 16) {
00159     *value = cacheBuffer_.fat16[cluster & 0XFF];
00160   } else {
00161     *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
00162   }
00163   return true;
00164 }
00165 //------------------------------------------------------------------------------
00166 // Store a FAT entry
00167 uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) {
00168   // error if reserved cluster
00169   if (cluster < 2) return false;
00170 
00171   // error if not in FAT
00172   if (cluster > (clusterCount_ + 1)) return false;
00173 
00174   // calculate block address for entry
00175   uint32_t lba = fatStartBlock_;
00176   lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7;
00177 
00178   if (lba != cacheBlockNumber_) {
00179     if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false;
00180   }
00181   // store entry
00182   if (fatType_ == 16) {
00183     cacheBuffer_.fat16[cluster & 0XFF] = value;
00184   } else {
00185     cacheBuffer_.fat32[cluster & 0X7F] = value;
00186   }
00187   cacheSetDirty();
00188 
00189   // mirror second FAT
00190   if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
00191   return true;
00192 }
00193 //------------------------------------------------------------------------------
00194 // free a cluster chain
00195 uint8_t SdVolume::freeChain(uint32_t cluster) {
00196   // clear free cluster location
00197   allocSearchStart_ = 2;
00198 
00199   do {
00200     uint32_t next;
00201     if (!fatGet(cluster, &next)) return false;
00202 
00203     // free cluster
00204     if (!fatPut(cluster, 0)) return false;
00205 
00206     cluster = next;
00207   } while (!isEOC(cluster));
00208 
00209   return true;
00210 }
00211 //------------------------------------------------------------------------------
00227 uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) {
00228   uint32_t volumeStartBlock = 0;
00229   sdCard_ = dev;
00230   // if part == 0 assume super floppy with FAT boot sector in block zero
00231   // if part > 0 assume mbr volume with partition table
00232   if (part) {
00233     if (part > 4)return false;
00234     if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
00235     part_t* p = &cacheBuffer_.mbr.part[part-1];
00236     if ((p->boot & 0X7F) !=0  ||
00237       p->totalSectors < 100 ||
00238       p->firstSector == 0) {
00239       // not a valid partition
00240       return false;
00241     }
00242     volumeStartBlock = p->firstSector;
00243   }
00244   if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false;
00245   bpb_t* bpb = &cacheBuffer_.fbs.bpb;
00246   if (bpb->bytesPerSector != 512 ||
00247     bpb->fatCount == 0 ||
00248     bpb->reservedSectorCount == 0 ||
00249     bpb->sectorsPerCluster == 0) {
00250        // not valid FAT volume
00251       return false;
00252   }
00253   fatCount_ = bpb->fatCount;
00254   blocksPerCluster_ = bpb->sectorsPerCluster;
00255 
00256   // determine shift that is same as multiply by blocksPerCluster_
00257   clusterSizeShift_ = 0;
00258   while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
00259     // error if not power of 2
00260     if (clusterSizeShift_++ > 7) return false;
00261   }
00262   blocksPerFat_ = bpb->sectorsPerFat16 ?
00263                     bpb->sectorsPerFat16 : bpb->sectorsPerFat32;
00264 
00265   fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount;
00266 
00267   // count for FAT16 zero for FAT32
00268   rootDirEntryCount_ = bpb->rootDirEntryCount;
00269 
00270   // directory start for FAT16 dataStart for FAT32
00271   rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_;
00272 
00273   // data start for FAT16 and FAT32
00274   dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512);
00275 
00276   // total blocks for FAT16 or FAT32
00277   uint32_t totalBlocks = bpb->totalSectors16 ?
00278                            bpb->totalSectors16 : bpb->totalSectors32;
00279   // total data blocks
00280   clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
00281 
00282   // divide by cluster size to get cluster count
00283   clusterCount_ >>= clusterSizeShift_;
00284 
00285   // FAT type is determined by cluster count
00286   if (clusterCount_ < 4085) {
00287     fatType_ = 12;
00288   } else if (clusterCount_ < 65525) {
00289     fatType_ = 16;
00290   } else {
00291     rootDirStart_ = bpb->fat32RootCluster;
00292     fatType_ = 32;
00293   }
00294   return true;
00295 }