2 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 /************************************************************************/
20 /* PROJECT : exFAT & FAT12/16/32 File System */
22 /* PURPOSE : sdFAT FAT entry manager */
24 /*----------------------------------------------------------------------*/
28 /************************************************************************/
30 #include <asm/unaligned.h>
35 /*----------------------------------------------------------------------*/
36 /* Global Variable Definitions */
37 /*----------------------------------------------------------------------*/
38 /* All buffer structures are protected w/ fsi->v_sem */
40 /*----------------------------------------------------------------------*/
41 /* Static functions */
42 /*----------------------------------------------------------------------*/
44 /*======================================================================*/
45 /* FAT Read/Write Functions */
46 /*======================================================================*/
49 * returns 0 on success, -1 on error
51 static s32
exfat_ent_get(struct super_block
*sb
, u32 loc
, u32
*content
)
53 u32 sec
, off
, _content
;
55 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
57 /* fsi->vol_type == EXFAT */
58 sec
= fsi
->FAT1_start_sector
+ (loc
>> (sb
->s_blocksize_bits
-2));
59 off
= (loc
<< 2) & (u32
)(sb
->s_blocksize
- 1);
61 fat_sector
= fcache_getblk(sb
, sec
);
65 _content
= le32_to_cpu(*(__le32
*)(&fat_sector
[off
]));
67 /* remap reserved clusters to simplify code */
68 if (_content
>= CLUSTER_32(0xFFFFFFF8))
71 *content
= CLUSTER_32(_content
);
75 static s32
exfat_ent_set(struct super_block
*sb
, u32 loc
, u32 content
)
80 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
82 sec
= fsi
->FAT1_start_sector
+ (loc
>> (sb
->s_blocksize_bits
-2));
83 off
= (loc
<< 2) & (u32
)(sb
->s_blocksize
- 1);
85 fat_sector
= fcache_getblk(sb
, sec
);
89 fat_entry
= (__le32
*)&(fat_sector
[off
]);
90 *fat_entry
= cpu_to_le32(content
);
92 return fcache_modify(sb
, sec
);
95 #define FATENT_FAT32_VALID_MASK (0x0FFFFFFFU)
96 #define FATENT_FAT32_IGNORE_MASK (0xF0000000U)
97 static s32
fat32_ent_get(struct super_block
*sb
, u32 loc
, u32
*content
)
99 u32 sec
, off
, _content
;
101 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
103 sec
= fsi
->FAT1_start_sector
+ (loc
>> (sb
->s_blocksize_bits
-2));
104 off
= (loc
<< 2) & (u32
)(sb
->s_blocksize
- 1);
106 fat_sector
= fcache_getblk(sb
, sec
);
110 _content
= le32_to_cpu(*(__le32
*)(&fat_sector
[off
]));
111 _content
&= FATENT_FAT32_VALID_MASK
;
113 /* remap reserved clusters to simplify code */
114 if (_content
== CLUSTER_32(0x0FFFFFF7U
))
116 else if (_content
>= CLUSTER_32(0x0FFFFFF8U
))
119 *content
= CLUSTER_32(_content
);
123 static s32
fat32_ent_set(struct super_block
*sb
, u32 loc
, u32 content
)
128 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
130 content
&= FATENT_FAT32_VALID_MASK
;
132 sec
= fsi
->FAT1_start_sector
+ (loc
>> (sb
->s_blocksize_bits
-2));
133 off
= (loc
<< 2) & (u32
)(sb
->s_blocksize
- 1);
135 fat_sector
= fcache_getblk(sb
, sec
);
139 fat_entry
= (__le32
*)&(fat_sector
[off
]);
140 content
|= (le32_to_cpu(*fat_entry
) & FATENT_FAT32_IGNORE_MASK
);
141 *fat_entry
= cpu_to_le32(content
);
143 return fcache_modify(sb
, sec
);
146 #define FATENT_FAT16_VALID_MASK (0x0000FFFFU)
147 static s32
fat16_ent_get(struct super_block
*sb
, u32 loc
, u32
*content
)
149 u32 sec
, off
, _content
;
151 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
153 sec
= fsi
->FAT1_start_sector
+ (loc
>> (sb
->s_blocksize_bits
-1));
154 off
= (loc
<< 1) & (u32
)(sb
->s_blocksize
- 1);
156 fat_sector
= fcache_getblk(sb
, sec
);
160 _content
= (u32
)le16_to_cpu(*(__le16
*)(&fat_sector
[off
]));
161 _content
&= FATENT_FAT16_VALID_MASK
;
163 /* remap reserved clusters to simplify code */
164 if (_content
== CLUSTER_16(0xFFF7U
))
166 else if (_content
>= CLUSTER_16(0xFFF8U
))
169 *content
= CLUSTER_32(_content
);
173 static s32
fat16_ent_set(struct super_block
*sb
, u32 loc
, u32 content
)
178 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
180 content
&= FATENT_FAT16_VALID_MASK
;
182 sec
= fsi
->FAT1_start_sector
+ (loc
>> (sb
->s_blocksize_bits
-1));
183 off
= (loc
<< 1) & (u32
)(sb
->s_blocksize
- 1);
185 fat_sector
= fcache_getblk(sb
, sec
);
189 fat_entry
= (__le16
*)&(fat_sector
[off
]);
190 *fat_entry
= cpu_to_le16(content
);
192 return fcache_modify(sb
, sec
);
195 #define FATENT_FAT12_VALID_MASK (0x00000FFFU)
196 static s32
fat12_ent_get(struct super_block
*sb
, u32 loc
, u32
*content
)
198 u32 sec
, off
, _content
;
200 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
202 sec
= fsi
->FAT1_start_sector
+ ((loc
+ (loc
>> 1)) >> sb
->s_blocksize_bits
);
203 off
= (loc
+ (loc
>> 1)) & (u32
)(sb
->s_blocksize
- 1);
205 fat_sector
= fcache_getblk(sb
, sec
);
209 if (off
== (u32
)(sb
->s_blocksize
- 1)) {
210 _content
= (u32
) fat_sector
[off
];
212 fat_sector
= fcache_getblk(sb
, ++sec
);
216 _content
|= (u32
) fat_sector
[0] << 8;
218 _content
= get_unaligned_le16(&fat_sector
[off
]);
224 _content
&= FATENT_FAT12_VALID_MASK
;
226 /* remap reserved clusters to simplify code */
227 if (_content
== CLUSTER_16(0x0FF7U
))
229 else if (_content
>= CLUSTER_16(0x0FF8U
))
232 *content
= CLUSTER_32(_content
);
236 static s32
fat12_ent_set(struct super_block
*sb
, u32 loc
, u32 content
)
239 u8
*fat_sector
, *fat_entry
;
240 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
242 content
&= FATENT_FAT12_VALID_MASK
;
244 sec
= fsi
->FAT1_start_sector
+ ((loc
+ (loc
>> 1)) >> sb
->s_blocksize_bits
);
245 off
= (loc
+ (loc
>> 1)) & (u32
)(sb
->s_blocksize
- 1);
247 fat_sector
= fcache_getblk(sb
, sec
);
251 if (loc
& 1) { /* odd */
255 if (off
== (u32
)(sb
->s_blocksize
-1)) {
256 fat_sector
[off
] = (u8
)(content
| (fat_sector
[off
] & 0x0F));
257 if (fcache_modify(sb
, sec
))
260 fat_sector
= fcache_getblk(sb
, ++sec
);
264 fat_sector
[0] = (u8
)(content
>> 8);
266 fat_entry
= &(fat_sector
[off
]);
267 content
|= 0x000F & get_unaligned_le16(fat_entry
);
268 put_unaligned_le16(content
, fat_entry
);
271 fat_sector
[off
] = (u8
)(content
);
273 if (off
== (u32
)(sb
->s_blocksize
-1)) {
274 fat_sector
[off
] = (u8
)(content
);
275 if (fcache_modify(sb
, sec
))
278 fat_sector
= fcache_getblk(sb
, ++sec
);
282 fat_sector
[0] = (u8
)((fat_sector
[0] & 0xF0) | (content
>> 8));
284 fat_entry
= &(fat_sector
[off
]);
285 content
|= 0xF000 & get_unaligned_le16(fat_entry
);
286 put_unaligned_le16(content
, fat_entry
);
289 return fcache_modify(sb
, sec
);
293 static FATENT_OPS_T fat12_ent_ops
= {
298 static FATENT_OPS_T fat16_ent_ops
= {
303 static FATENT_OPS_T fat32_ent_ops
= {
308 static FATENT_OPS_T exfat_ent_ops
= {
313 s32
fat_ent_ops_init(struct super_block
*sb
)
315 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
317 switch (fsi
->vol_type
) {
319 fsi
->fatent_ops
= &exfat_ent_ops
;
322 fsi
->fatent_ops
= &fat32_ent_ops
;
325 fsi
->fatent_ops
= &fat16_ent_ops
;
328 fsi
->fatent_ops
= &fat12_ent_ops
;
331 fsi
->fatent_ops
= NULL
;
332 EMSG("Unknown volume type : %d", (int)fsi
->vol_type
);
339 static inline bool is_reserved_clus(u32 clus
)
341 if (IS_CLUS_FREE(clus
))
343 if (IS_CLUS_EOF(clus
))
345 if (IS_CLUS_BAD(clus
))
350 static inline bool is_valid_clus(FS_INFO_T
*fsi
, u32 clus
)
352 if (clus
< CLUS_BASE
|| fsi
->num_clusters
<= clus
)
357 s32
fat_ent_get(struct super_block
*sb
, u32 loc
, u32
*content
)
359 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
362 if (!is_valid_clus(fsi
, loc
)) {
363 sdfat_fs_error(sb
, "invalid access to FAT (entry 0x%08x)", loc
);
367 err
= fsi
->fatent_ops
->ent_get(sb
, loc
, content
);
369 sdfat_fs_error(sb
, "failed to access to FAT "
370 "(entry 0x%08x, err:%d)", loc
, err
);
374 if (!is_reserved_clus(*content
) && !is_valid_clus(fsi
, *content
)) {
375 sdfat_fs_error(sb
, "invalid access to FAT (entry 0x%08x) "
376 "bogus content (0x%08x)", loc
, *content
);
383 s32
fat_ent_set(struct super_block
*sb
, u32 loc
, u32 content
)
385 FS_INFO_T
*fsi
= &(SDFAT_SB(sb
)->fsi
);
387 return fsi
->fatent_ops
->ent_set(sb
, loc
, content
);
390 s32
fat_ent_get_safe(struct super_block
*sb
, u32 loc
, u32
*content
)
392 s32 err
= fat_ent_get(sb
, loc
, content
);
397 if (IS_CLUS_FREE(*content
)) {
398 sdfat_fs_error(sb
, "invalid access to FAT free cluster "
399 "(entry 0x%08x)", loc
);
403 if (IS_CLUS_BAD(*content
)) {
404 sdfat_fs_error(sb
, "invalid access to FAT bad cluster "
405 "(entry 0x%08x)", loc
);
412 /* end of fatent.c */