📄 fatfs_supp.c
字号:
cyg_uint32 block, block_pos;
cluster_to_block_pos(disk, cluster, cluster_pos, &block, &block_pos);
return cyg_blib_read(&disk->blib, buf, len, block, block_pos);
}
// -------------------------------------------------------------------------
// jdays_to_gdate()
// Converts juilan days into gregorian date.
static void
jdays_to_gdate(cyg_uint32 jd, int *day, int *month, int *year)
{
cyg_uint32 l, n, i, j;
l = jd + 68569;
n = (4 * l) / 146097;
l = l - (146097 * n + 3) / 4;
i = (4000 * (l + 1)) / 1461001;
l = l - (1461 * i) / 4 + 31;
j = (80 * l) / 2447;
*day = l - (2447 * j) / 80;
l = j / 11;
*month = j + 2 - (12 * l);
*year = 100 * (n - 49) + i + l;
}
// -------------------------------------------------------------------------
// gdate_to_jdays()
// Converts gregorian date to juilan days.
static void
gdate_to_jdays(int day, int month, int year, cyg_uint32 *jd)
{
*jd = day - 32075 + 1461*(year + 4800 + (month - 14)/12)/4 +
367*(month - 2 - (month - 14)/12*12)/12 -
3*((year + 4900 + (month - 14)/12)/100)/4;
}
// -------------------------------------------------------------------------
// date_unix2dos()
// Converts unix timestamp to dos time and date.
static void
date_unix2dos(time_t unix_timestamp,
cyg_uint16 *dos_time,
cyg_uint16 *dos_date)
{
cyg_uint32 jd;
cyg_uint16 dtime, ddate;
int hour, min, sec;
int day, month, year;
hour = (unix_timestamp / 3600) % 24;
min = (unix_timestamp / 60) % 60;
sec = unix_timestamp % 60;
jd = JD_1_JAN_1970 + unix_timestamp / (3600 * 24);
jdays_to_gdate(jd, &day, &month, &year);
CYG_TRACE7(TDE, "timestamp=%d date=%d:%d:%d %d-%d-%d",
unix_timestamp, hour, min, sec, year, month, day);
if (year < 1980)
year = 1980;
dtime = (hour << 11) | (min << 5) | (sec >> 1);
ddate = ((year - 1980) << 9) | (month << 5) | day;
CYG_TRACE2(TDE, "dos time=%d date=%d", dtime, ddate);
if (NULL != dos_time) *dos_time = dtime;
if (NULL != dos_date) *dos_date = ddate;
}
// -------------------------------------------------------------------------
// date_dos2unix()
// Converts dos time and date to unix timestamp.
static void
date_dos2unix(cyg_uint16 dos_time,
cyg_uint16 dos_date,
time_t *unix_timestamp)
{
cyg_uint32 ts;
int hour, min, sec;
int day, month, year;
sec = (dos_time & ((1<<5)-1)) * 2;
dos_time >>= 5;
min = (dos_time & ((1<<6)-1));
dos_time >>= 6;
hour = dos_time;
day = (dos_date & ((1<<5)-1));
dos_date >>= 5;
month = (dos_date & ((1<<4)-1));
dos_date >>= 4;
year = dos_date + 1980;
gdate_to_jdays(day, month, year, &ts);
ts -= JD_1_JAN_1970;
ts = (ts * 24 * 3600) + (sec + min * 60 + hour * 3600);
*unix_timestamp = ts;
CYG_TRACE2(TDE, "dos time=%d date=%d", dos_time, dos_date);
CYG_TRACE7(TDE, "timestamp=%d date=%d:%d:%d %d-%d-%d",
ts, hour, min, sec, year, month, day);
}
//==========================================================================
// FAT boot record functions
#if TDE
// -------------------------------------------------------------------------
// print_boot_record()
// Prints FAT boot record.
static void
print_boot_record(fat_boot_record_t* fbr)
{
diag_printf("FAT: FBR jump code: 0x%02X\n", fbr->jump);
diag_printf("FAT: FBR oem name: '%.8s'\n", fbr->oem_name);
diag_printf("FAT: FBR bytes per sec: %u\n", fbr->bytes_per_sec);
diag_printf("FAT: FBR sec per cluster: %u\n", fbr->sec_per_clu);
diag_printf("FAT: FBR reserved sec: %u\n", fbr->res_sec_num);
diag_printf("FAT: FBR fat tbls num: %u\n", fbr->fat_tbls_num);
diag_printf("FAT: FBR max root dents: %u\n", fbr->max_root_dents);
diag_printf("FAT: FBR sec num (32): %u\n", fbr->sec_num_32);
diag_printf("FAT: FBR media desc: 0x%02X\n", fbr->media_desc);
diag_printf("FAT: FBR sec per fat: %u\n", fbr->sec_per_fat);
diag_printf("FAT: FBR sec per track: %u\n", fbr->sec_per_track);
diag_printf("FAT: FBR heads num: %u\n", fbr->heads_num);
diag_printf("FAT: FBR hidden sec num: %u\n", fbr->hsec_num);
diag_printf("FAT: FBR sec num: %u\n", fbr->sec_num);
if (0 == fbr->sec_per_fat)
{
diag_printf("FAT: FBR sec per fat32: %u\n", fbr->sec_per_fat_32);
diag_printf("FAT: FBR ext flags: 0x%04X\n", fbr->ext_flags);
diag_printf("FAT: FBR fs ver: %u\n", fbr->fs_ver);
diag_printf("FAT: FBR root cluster: %u\n", fbr->root_cluster);
diag_printf("FAT: FBR fs info sec: %u\n", fbr->fs_info_sec);
}
diag_printf("FAT: FBR drv num: %u\n", fbr->drv_num);
diag_printf("FAT: FBR ext sig: 0x%02X\n", fbr->ext_sig);
diag_printf("FAT: FBR ser num: 0x%08X\n", fbr->ser_num);
diag_printf("FAT: FBR vol name: '%.11s'\n", fbr->vol_name);
diag_printf("FAT: FBR fat name: '%.8s'\n", fbr->fat_name);
diag_printf("FAT: FBR exe mark: 0x%02X 0x%02X\n",
fbr->exe_marker[0], fbr->exe_marker[1]);
}
#endif // TDE
// -------------------------------------------------------------------------
// read_boot_record()
// Reads FAT boot record from disk.
static int
read_boot_record(fatfs_disk_t *disk, fat_boot_record_t *fbr)
{
cyg_uint8 data[0x5A];
cyg_uint32 len;
int err;
len = 0x5A;
err = disk_read(disk, (void*)data, &len, 0);
if (err != ENOERR)
return err;
GET_WORD(data, fbr->jump, 0x00);
GET_BYTES(data, fbr->oem_name, 8, 0x03);
GET_WORD(data, fbr->bytes_per_sec, 0x0B);
GET_BYTE(data, fbr->sec_per_clu, 0x0D);
GET_WORD(data, fbr->res_sec_num, 0x0E);
GET_BYTE(data, fbr->fat_tbls_num, 0x10);
GET_WORD(data, fbr->max_root_dents, 0x11);
GET_WORD(data, fbr->sec_num_32, 0x13);
GET_BYTE(data, fbr->media_desc, 0x15);
GET_WORD(data, fbr->sec_per_fat, 0x16);
GET_WORD(data, fbr->sec_per_track, 0x18);
GET_WORD(data, fbr->heads_num, 0x1A);
GET_DWORD(data, fbr->hsec_num, 0x1C);
GET_DWORD(data, fbr->sec_num, 0x20);
// This is a quick check for FAT12/16 or FAT32 boot record.
// The sec_per_fat field must be 0 on FAT32, since this
// field plays a crucial role in detection of the FAT type
// (12,16,32) it is quite safe to make this assumption.
if (0 == fbr->sec_per_fat)
{
GET_DWORD(data, fbr->sec_per_fat_32, 0x24);
GET_WORD(data, fbr->ext_flags, 0x28);
GET_WORD(data, fbr->fs_ver, 0x2A);
GET_DWORD(data, fbr->root_cluster, 0x2C);
GET_WORD(data, fbr->fs_info_sec, 0x30);
GET_WORD(data, fbr->bk_boot_sec, 0x32);
GET_BYTE(data, fbr->drv_num, 0x40);
GET_BYTE(data, fbr->ext_sig, 0x42);
GET_DWORD(data, fbr->ser_num, 0x43);
GET_BYTES(data, fbr->vol_name, 11, 0x47);
GET_BYTES(data, fbr->fat_name, 8, 0x52);
}
else
{
GET_BYTE(data, fbr->drv_num, 0x24);
GET_BYTE(data, fbr->ext_sig, 0x26);
GET_DWORD(data, fbr->ser_num, 0x27);
GET_BYTES(data, fbr->vol_name, 11, 0x2B);
GET_BYTES(data, fbr->fat_name, 8, 0x36);
}
// Read the end marker
len = 0x02;
err = disk_read(disk, (void*)data, &len, 0x1FE);
if (err != ENOERR)
return err;
GET_BYTES(data, fbr->exe_marker, 2, 0);
// Zero terminate strings
fbr->oem_name[8] = '\0';
fbr->vol_name[11] = '\0';
fbr->fat_name[8] = '\0';
#if TDE
print_boot_record(fbr);
#endif
return ENOERR;
}
//==========================================================================
// FAT table entry functions
// -------------------------------------------------------------------------
// read_tentry()
// Reads FAT table entry from disk.
static int
read_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
{
cyg_uint8 data[4];
cyg_uint32 pos, num3;
cyg_uint32 e;
cyg_uint32 len;
int err;
switch (disk->fat_type)
{
case FATFS_FAT12:
num3 = num * 3;
pos = disk->fat_tbl_pos + (num3 >> 1);
len = 2;
err = disk_read(disk, (void*)data, &len, pos);
if (err != ENOERR)
return err;
GET_WORD(data, e, 0x00);
if (0 == (num3 & 1)) *entry = e & 0x0FFF;
else *entry = (e >> 4) & 0x0FFF;
break;
case FATFS_FAT16:
pos = disk->fat_tbl_pos + (num << 1);
len = 2;
err = disk_read(disk, (void*)data, &len, pos);
if (err != ENOERR)
return err;
GET_WORD(data, e, 0x00);
*entry = e;
break;
case FATFS_FAT32:
pos = disk->fat_tbl_pos + (num << 2);
len = 4;
err = disk_read(disk, (void*)data, &len, pos);
if (err != ENOERR)
return err;
GET_DWORD(data, e, 0x00);
*entry = e & 0x0FFFFFFF;
break;
default:
CYG_ASSERT(false, "Unknown FAT type");
}
return ENOERR;
}
// -------------------------------------------------------------------------
// write_tentry()
// Writes FAT table entry to disk (to all copies of FAT).
static int
write_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
{
cyg_uint8 data[4];
cyg_uint32 pos=0, num3;
cyg_uint32 e;
cyg_uint32 len;
int i;
int err;
switch (disk->fat_type)
{
case FATFS_FAT12:
num3 = num * 3;
pos = disk->fat_tbl_pos + (num3 >> 1);
len = 2;
err = disk_read(disk, (void*)data, &len, pos);
if (err != ENOERR)
return err;
GET_WORD(data, e, 0x00);
if (0 == (num3 & 1)) e = (e & 0xF000) | (*entry & 0x0FFF);
else e = (e & 0x000F) | ((*entry & 0x0FFF) << 4);
SET_WORD(data, e, 0x00);
break;
case FATFS_FAT16:
pos = disk->fat_tbl_pos + (num << 1);
len = 2;
e = *entry;
SET_WORD(data, e, 0x00);
break;
case FATFS_FAT32:
pos = disk->fat_tbl_pos + (num << 2);
len = 4;
err = disk_read(disk, (void*)data, &len, pos);
if (err != ENOERR)
return err;
GET_DWORD(data, e, 0x00);
e = (e & 0xF0000000) | *entry;
SET_DWORD(data, e, 0x00);
break;
default:
CYG_ASSERT(false, "Unknown FAT type");
}
for (i = 0; i < disk->fat_tbls_num; i++)
{
err = disk_write(disk, (void*)data, &len, pos);
if (err != ENOERR)
return err;
pos += disk->fat_tbl_size;
}
return ENOERR;
}
// -------------------------------------------------------------------------
// get_tentry_type()
// Gets the type of FAT table entry.
static int
get_tentry_type(fatfs_disk_t *disk, cyg_uint32 entry)
{
int type;
switch (disk->fat_type)
{
case FATFS_FAT12:
if (entry < 0x0FF0)
{
if (0x0000 == entry) type = TENTRY_FREE;
else type = TENTRY_REGULAR;
}
else if (entry >= 0x0FF8) type = TENTRY_LAST;
else if (0x0FF7 == entry) type = TENTRY_BAD;
else type = TENTRY_RESERVED;
break;
case FATFS_FAT16:
if (entry < 0xFFF0)
{
if (0x0000 == entry) type = TENTRY_FREE;
else type = TENTRY_REGULAR;
}
else if (entry >= 0xFFF8) type = TENTRY_LAST;
else if (0xFFF7 == entry) type = TENTRY_BAD;
else type = TENTRY_RESERVED;
break;
case FATFS_FAT32:
if (entry < 0x0FFFFFF0)
{
if (0x00000000 == entry) type = TENTRY_FREE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -