⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fatfs_supp.c

📁 嵌入式FAT文件系统
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 + -