2 * Acess2 FAT12/16/32 Driver
3 * - By John Hodge (thePowersGang)
6 * - FAT Manipulation and Cluster IO
15 * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
16 * \brief Fetches a value from the FAT
18 Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
22 ENTER("pDisk xCluster", Disk, cluster);
24 Mutex_Acquire( &Disk->lFAT );
26 if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
28 val = Disk->FATCache[cluster];
29 if(Disk->type == FAT12 && val == EOC_FAT12) val = GETFATVALUE_EOC;
30 if(Disk->type == FAT16 && val == EOC_FAT16) val = GETFATVALUE_EOC;
31 if(Disk->type == FAT32 && val == EOC_FAT32) val = GETFATVALUE_EOC;
36 ofs = Disk->bootsect.resvSectCount*512;
37 if(Disk->type == FAT12) {
38 VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);
39 LOG("3 bytes at 0x%x are (Uint32)0x%x", ofs+(cluster/2)*3, val);
40 val = (cluster & 1) ? (val>>12) : (val & 0xFFF);
41 if(val == EOC_FAT12) val = GETFATVALUE_EOC;
42 } else if(Disk->type == FAT16) {
43 VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);
44 if(val == EOC_FAT16) val = GETFATVALUE_EOC;
46 VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);
47 if(val == EOC_FAT32) val = GETFATVALUE_EOC;
52 Mutex_Release( &Disk->lFAT );
59 * \brief Allocate a new cluster
61 Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)
66 if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
68 int bFoundCluster = 0;
73 case FAT12: eoc = EOC_FAT12; break;
74 case FAT16: eoc = EOC_FAT16; break;
75 case FAT32: eoc = EOC_FAT32; break;
79 Mutex_Acquire(&Disk->lFAT);
82 for(ret = Previous; ret < Disk->ClusterCount; ret++)
84 if(Disk->FATCache[ret] != 0) {
92 for(ret = 0; ret < Previous; ret++)
94 if(Disk->FATCache[ret] == 0) {
103 Disk->FATCache[ret] = eoc;
105 Disk->FATCache[Previous] = ret;
112 Mutex_Release(&Disk->lFAT);
113 LOG("Allocated cluster %x", ret);
120 Uint32 base = Disk->bootsect.resvSectCount*512;
121 int block = 0, block_ofs = 0;
123 const int block_size = 512*3;
124 const int ents_per_block_12 = block_size * 2 / 3; // 1.5 bytes per entry
125 // const int ents_per_block_16 = block_size / 2; // 2 bytes per entry
126 // const int ents_per_block_32 = block_size / 4; // 4 bytes per entry
127 int block_count_12 = DivUp(Disk->ClusterCount, ents_per_block_12);
128 Uint8 sector_data[block_size+1];
129 sector_data[block_size] = 0;
131 Mutex_Acquire(&Disk->lFAT);
136 block = Previous / ents_per_block_12;
141 // Search within the same block as the previous cluster first
143 VFS_ReadAt(Disk->fileHandle, base + block*block_size, block_size, sector_data);
144 for( block_ofs = 0; block_ofs < ents_per_block_12; block_ofs ++ )
146 Uint32 *valptr = (void*)( sector_data + block_ofs / 2 * 3 );
147 int bitofs = 12 * (block_ofs % 2);
148 // LOG("%i:%i - FAT Ent 0x%03x", block, block_ofs, (*valptr>>bitofs) & 0xFFF);
149 if( ((*valptr >> bitofs) & 0xFFF) == 0 ) {
150 // Found a free cluster
151 *valptr |= EOC_FAT12 << bitofs;
152 ret = block * ents_per_block_12 + block_ofs;
156 // Check for early break from the above loop
157 if( block_ofs != ents_per_block_12 )
162 if( block == block_count_12 )
164 } while( block != first_block );
166 if( ret != 0 ) // TODO: Could cluster 0 be valid?
168 // Write back changes to this part of the FAT
169 VFS_WriteAt(Disk->fileHandle, base + block, block_size, sector_data);
171 // Note the new cluster in the chain
174 LOG("Updating cluster %x to point to %x (offset %x)", Previous, ret,
175 base + (Previous>>1)*3);
176 VFS_ReadAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val);
185 VFS_WriteAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val);
190 Log_Warning("FAT", "TODO: Implement cluster allocation with FAT16");
191 // VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);
192 // VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);
195 Log_Warning("FAT", "TODO: Implement cluster allocation with FAT32");
196 // VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);
197 // VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);
200 Mutex_Release(&Disk->lFAT);
201 LOG("Allocated cluster %x", ret);
209 * \brief Free's a cluster
210 * \return The original contents of the cluster
212 Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)
216 if( Cluster < 2 || Cluster > Disk->ClusterCount ) // oops?
218 Log_Notice("FAT", "Cluster 0x%x is out of range (2 ... 0x%x)",
219 Cluster, Disk->ClusterCount-1);
223 Mutex_Acquire(&Disk->lFAT);
225 if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
228 ret = Disk->FATCache[Cluster];
229 Disk->FATCache[Cluster] = 0;
235 Uint32 ofs = Disk->bootsect.resvSectCount*512;
239 VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
240 val = LittleEndian32(val);
242 ret = (val >> 12) & 0xFFF;
249 val = LittleEndian32(val);
250 VFS_WriteAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
253 VFS_ReadAt(Disk->fileHandle, ofs+Cluster*2, 2, &ret);
254 ret = LittleEndian16(ret);
256 VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);
259 VFS_ReadAt(Disk->fileHandle, ofs+Cluster*4, 4, &ret);
260 ret = LittleEndian32(ret);
262 VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 4, &val);
268 Mutex_Release(&Disk->lFAT);
269 LOG("ret = %07x, eoc = %07x", ret, EOC_FAT12);
271 Log_Notice("FAT", "Cluster 0x%x was already free", Cluster);
274 if(Disk->type == FAT12 && ret == EOC_FAT12) ret = -1;
275 if(Disk->type == FAT16 && ret == EOC_FAT16) ret = -1;
276 if(Disk->type == FAT32 && ret == EOC_FAT32) ret = -1;
277 LOG("ret = %07x", ret);
283 * ====================
285 * ====================
288 * \brief Read a cluster
289 * \param Disk Disk (Volume) to read from
290 * \param Length Length to read
291 * \param Buffer Destination for read data
293 void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)
295 ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);
298 (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
299 * Disk->bootsect.bps,
308 * \brief Write a cluster to disk
310 void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, const void *Buffer)
312 ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);
315 (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
316 * Disk->bootsect.bps,
317 Disk->BytesPerCluster,