|
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 |