SdVolume.cpp

changeset 0
2c8ba1964db7
equal deleted inserted replaced
-1:000000000000 0:2c8ba1964db7
1 /* Arduino SdFat Library
2 * Copyright (C) 2009 by William Greiman
3 *
4 * This file is part of the Arduino SdFat Library
5 *
6 * This Library is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This Library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with the Arduino SdFat Library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20 #include "Marlin.h"
21 #ifdef SDSUPPORT
22
23 #include "SdVolume.h"
24 //------------------------------------------------------------------------------
25 #if !USE_MULTIPLE_CARDS
26 // raw block cache
27 uint32_t SdVolume::cacheBlockNumber_; // current block number
28 cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
29 Sd2Card* SdVolume::sdCard_; // pointer to SD card object
30 bool SdVolume::cacheDirty_; // cacheFlush() will write block if true
31 uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT
32 #endif // USE_MULTIPLE_CARDS
33 //------------------------------------------------------------------------------
34 // find a contiguous group of clusters
35 bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
36 // start of group
37 uint32_t bgnCluster;
38 // end of group
39 uint32_t endCluster;
40 // last cluster of FAT
41 uint32_t fatEnd = clusterCount_ + 1;
42
43 // flag to save place to start next search
44 bool setStart;
45
46 // set search start cluster
47 if (*curCluster) {
48 // try to make file contiguous
49 bgnCluster = *curCluster + 1;
50
51 // don't save new start location
52 setStart = false;
53 } else {
54 // start at likely place for free cluster
55 bgnCluster = allocSearchStart_;
56
57 // save next search start if one cluster
58 setStart = count == 1;
59 }
60 // end of group
61 endCluster = bgnCluster;
62
63 // search the FAT for free clusters
64 for (uint32_t n = 0;; n++, endCluster++) {
65 // can't find space checked all clusters
66 if (n >= clusterCount_) goto fail;
67
68 // past end - start from beginning of FAT
69 if (endCluster > fatEnd) {
70 bgnCluster = endCluster = 2;
71 }
72 uint32_t f;
73 if (!fatGet(endCluster, &f)) goto fail;
74
75 if (f != 0) {
76 // cluster in use try next cluster as bgnCluster
77 bgnCluster = endCluster + 1;
78 } else if ((endCluster - bgnCluster + 1) == count) {
79 // done - found space
80 break;
81 }
82 }
83 // mark end of chain
84 if (!fatPutEOC(endCluster)) goto fail;
85
86 // link clusters
87 while (endCluster > bgnCluster) {
88 if (!fatPut(endCluster - 1, endCluster)) goto fail;
89 endCluster--;
90 }
91 if (*curCluster != 0) {
92 // connect chains
93 if (!fatPut(*curCluster, bgnCluster)) goto fail;
94 }
95 // return first cluster number to caller
96 *curCluster = bgnCluster;
97
98 // remember possible next free cluster
99 if (setStart) allocSearchStart_ = bgnCluster + 1;
100
101 return true;
102
103 fail:
104 return false;
105 }
106 //------------------------------------------------------------------------------
107 bool SdVolume::cacheFlush() {
108 if (cacheDirty_) {
109 if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
110 goto fail;
111 }
112 // mirror FAT tables
113 if (cacheMirrorBlock_) {
114 if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
115 goto fail;
116 }
117 cacheMirrorBlock_ = 0;
118 }
119 cacheDirty_ = 0;
120 }
121 return true;
122
123 fail:
124 return false;
125 }
126 //------------------------------------------------------------------------------
127 bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) {
128 if (cacheBlockNumber_ != blockNumber) {
129 if (!cacheFlush()) goto fail;
130 if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail;
131 cacheBlockNumber_ = blockNumber;
132 }
133 if (dirty) cacheDirty_ = true;
134 return true;
135
136 fail:
137 return false;
138 }
139 //------------------------------------------------------------------------------
140 // return the size in bytes of a cluster chain
141 bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) {
142 uint32_t s = 0;
143 do {
144 if (!fatGet(cluster, &cluster)) goto fail;
145 s += 512UL << clusterSizeShift_;
146 } while (!isEOC(cluster));
147 *size = s;
148 return true;
149
150 fail:
151 return false;
152 }
153 //------------------------------------------------------------------------------
154 // Fetch a FAT entry
155 bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
156 uint32_t lba;
157 if (cluster > (clusterCount_ + 1)) goto fail;
158 if (FAT12_SUPPORT && fatType_ == 12) {
159 uint16_t index = cluster;
160 index += index >> 1;
161 lba = fatStartBlock_ + (index >> 9);
162 if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
163 index &= 0X1FF;
164 uint16_t tmp = cacheBuffer_.data[index];
165 index++;
166 if (index == 512) {
167 if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail;
168 index = 0;
169 }
170 tmp |= cacheBuffer_.data[index] << 8;
171 *value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
172 return true;
173 }
174 if (fatType_ == 16) {
175 lba = fatStartBlock_ + (cluster >> 8);
176 } else if (fatType_ == 32) {
177 lba = fatStartBlock_ + (cluster >> 7);
178 } else {
179 goto fail;
180 }
181 if (lba != cacheBlockNumber_) {
182 if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
183 }
184 if (fatType_ == 16) {
185 *value = cacheBuffer_.fat16[cluster & 0XFF];
186 } else {
187 *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
188 }
189 return true;
190
191 fail:
192 return false;
193 }
194 //------------------------------------------------------------------------------
195 // Store a FAT entry
196 bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
197 uint32_t lba;
198 // error if reserved cluster
199 if (cluster < 2) goto fail;
200
201 // error if not in FAT
202 if (cluster > (clusterCount_ + 1)) goto fail;
203
204 if (FAT12_SUPPORT && fatType_ == 12) {
205 uint16_t index = cluster;
206 index += index >> 1;
207 lba = fatStartBlock_ + (index >> 9);
208 if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
209 // mirror second FAT
210 if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
211 index &= 0X1FF;
212 uint8_t tmp = value;
213 if (cluster & 1) {
214 tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4;
215 }
216 cacheBuffer_.data[index] = tmp;
217 index++;
218 if (index == 512) {
219 lba++;
220 index = 0;
221 if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
222 // mirror second FAT
223 if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
224 }
225 tmp = value >> 4;
226 if (!(cluster & 1)) {
227 tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4;
228 }
229 cacheBuffer_.data[index] = tmp;
230 return true;
231 }
232 if (fatType_ == 16) {
233 lba = fatStartBlock_ + (cluster >> 8);
234 } else if (fatType_ == 32) {
235 lba = fatStartBlock_ + (cluster >> 7);
236 } else {
237 goto fail;
238 }
239 if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
240 // store entry
241 if (fatType_ == 16) {
242 cacheBuffer_.fat16[cluster & 0XFF] = value;
243 } else {
244 cacheBuffer_.fat32[cluster & 0X7F] = value;
245 }
246 // mirror second FAT
247 if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
248 return true;
249
250 fail:
251 return false;
252 }
253 //------------------------------------------------------------------------------
254 // free a cluster chain
255 bool SdVolume::freeChain(uint32_t cluster) {
256 uint32_t next;
257
258 // clear free cluster location
259 allocSearchStart_ = 2;
260
261 do {
262 if (!fatGet(cluster, &next)) goto fail;
263
264 // free cluster
265 if (!fatPut(cluster, 0)) goto fail;
266
267 cluster = next;
268 } while (!isEOC(cluster));
269
270 return true;
271
272 fail:
273 return false;
274 }
275 //------------------------------------------------------------------------------
276 /** Volume free space in clusters.
277 *
278 * \return Count of free clusters for success or -1 if an error occurs.
279 */
280 int32_t SdVolume::freeClusterCount() {
281 uint32_t free = 0;
282 uint16_t n;
283 uint32_t todo = clusterCount_ + 2;
284
285 if (fatType_ == 16) {
286 n = 256;
287 } else if (fatType_ == 32) {
288 n = 128;
289 } else {
290 // put FAT12 here
291 return -1;
292 }
293
294 for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) {
295 if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1;
296 if (todo < n) n = todo;
297 if (fatType_ == 16) {
298 for (uint16_t i = 0; i < n; i++) {
299 if (cacheBuffer_.fat16[i] == 0) free++;
300 }
301 } else {
302 for (uint16_t i = 0; i < n; i++) {
303 if (cacheBuffer_.fat32[i] == 0) free++;
304 }
305 }
306 }
307 return free;
308 }
309 //------------------------------------------------------------------------------
310 /** Initialize a FAT volume.
311 *
312 * \param[in] dev The SD card where the volume is located.
313 *
314 * \param[in] part The partition to be used. Legal values for \a part are
315 * 1-4 to use the corresponding partition on a device formatted with
316 * a MBR, Master Boot Record, or zero if the device is formatted as
317 * a super floppy with the FAT boot sector in block zero.
318 *
319 * \return The value one, true, is returned for success and
320 * the value zero, false, is returned for failure. Reasons for
321 * failure include not finding a valid partition, not finding a valid
322 * FAT file system in the specified partition or an I/O error.
323 */
324 bool SdVolume::init(Sd2Card* dev, uint8_t part) {
325 uint32_t totalBlocks;
326 uint32_t volumeStartBlock = 0;
327 fat32_boot_t* fbs;
328
329 sdCard_ = dev;
330 fatType_ = 0;
331 allocSearchStart_ = 2;
332 cacheDirty_ = 0; // cacheFlush() will write block if true
333 cacheMirrorBlock_ = 0;
334 cacheBlockNumber_ = 0XFFFFFFFF;
335
336 // if part == 0 assume super floppy with FAT boot sector in block zero
337 // if part > 0 assume mbr volume with partition table
338 if (part) {
339 if (part > 4)goto fail;
340 if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
341 part_t* p = &cacheBuffer_.mbr.part[part-1];
342 if ((p->boot & 0X7F) !=0 ||
343 p->totalSectors < 100 ||
344 p->firstSector == 0) {
345 // not a valid partition
346 goto fail;
347 }
348 volumeStartBlock = p->firstSector;
349 }
350 if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
351 fbs = &cacheBuffer_.fbs32;
352 if (fbs->bytesPerSector != 512 ||
353 fbs->fatCount == 0 ||
354 fbs->reservedSectorCount == 0 ||
355 fbs->sectorsPerCluster == 0) {
356 // not valid FAT volume
357 goto fail;
358 }
359 fatCount_ = fbs->fatCount;
360 blocksPerCluster_ = fbs->sectorsPerCluster;
361 // determine shift that is same as multiply by blocksPerCluster_
362 clusterSizeShift_ = 0;
363 while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
364 // error if not power of 2
365 if (clusterSizeShift_++ > 7) goto fail;
366 }
367 blocksPerFat_ = fbs->sectorsPerFat16 ?
368 fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
369
370 fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount;
371
372 // count for FAT16 zero for FAT32
373 rootDirEntryCount_ = fbs->rootDirEntryCount;
374
375 // directory start for FAT16 dataStart for FAT32
376 rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_;
377
378 // data start for FAT16 and FAT32
379 dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512);
380
381 // total blocks for FAT16 or FAT32
382 totalBlocks = fbs->totalSectors16 ?
383 fbs->totalSectors16 : fbs->totalSectors32;
384 // total data blocks
385 clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
386
387 // divide by cluster size to get cluster count
388 clusterCount_ >>= clusterSizeShift_;
389
390 // FAT type is determined by cluster count
391 if (clusterCount_ < 4085) {
392 fatType_ = 12;
393 if (!FAT12_SUPPORT) goto fail;
394 } else if (clusterCount_ < 65525) {
395 fatType_ = 16;
396 } else {
397 rootDirStart_ = fbs->fat32RootCluster;
398 fatType_ = 32;
399 }
400 return true;
401
402 fail:
403 return false;
404 }
405 #endif

mercurial