?? fat.c
字號:
/*
* Copyright (c) 2003-2004 K. John '2B|!2B' Crispin
* Copyright (c) 2005 Stephan Dobretsberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
*
* Feedback, Bugs, ... mail stephan.dobretsberger@gmx.at
*
*/
#include "types.h"
#include "mmc.h"
#include "vs1001.h"
#include "spi.h"
#include "fat.h"
#include "test.h"
u08 fat_buf[FAT_RD_BUF_SIZE+1];
// starts by scanning the BPB
// sector needs to be equal to the first sector of the first partition
// use fat_get_part_start to get this value
//
// the first fat32 sector is set up as follows -->
// u08 jmpboot[3] 0xEB 0x?? 0x90 -- instructions to jump to the boot loader
// u08 OEMName[8] -- identifies system that formatted the card
// u08 BPB[42] -- BIOS Parameter Block -- see below
// .
// .
// .
// u08 0xAA -- signature
// u08 0x55 -- signature
//
// fat32 BPB -->
// u08 bytes_per_sec[2] -- the size of a sector. for MMC this is always 512
// u08 sec_per_clus -- the number of sectrs per cluster. for MMC normally 1
// u08 rsvd_sec[2] -- reserved sectors for additional boot code. fat32 normally has 32 sectors
// u08 num_fats -- number of fat-chains on the disk ? leave at 2 to be sure
// u08 root_dir_ent[2] -- 0 for fat32. used by fat16
// u08 tot_sec_16[2] -- 0 for fat32. used by fat16
// u08 media_type -- used by OS to determine removeable, fixed ... used by msdos 1.x
// u08 sec_per_fat[2] -- 0 for fat32. used by fat16
// u08 sec_per_track[2] -- something for geometry ?
// u08 num_heads[2] -- number of heads.
// u08 hidden_secs[4] -- something for HW int 0x13
// u08 tot_sec_32[4] -- the number of sectors on this partition
// u08 sec_per_fat_32[4] -- sectors per fat
// u08 ext_flags[2] -- extended partition ?
// u08 fs_ver[2] -- ?? something for fs
// u08 root_clus[4] -- offset to the sector that contains the root directory
// u08 fs_inf[2] -- ?? something for fs
// u08 bpb_bak[2] -- backup of bpb in reserved area of media
// defines for the offsets of the values in the bpb that we are interested in
#define FAT_OEM_START 3
#define FAT_OEM_STOP 10
#define FAT_BYTES_PER_SECTOR 11
#define FAT_SEC_PER_CLUS 13
#define FAT_RSVD_SEC_CNT 14
#define FAT_NUM_FATS 16
#define FAT_ROOT_ENT_CNT 17
#define FAT_TOTSEC 32
#define FAT_SIZE 36
#define FAT_ROOT_CLUS 44
// file attribs
#define FAT_READ_ONLY 0x01
#define FAT_HIDDEN 0x02
#define FAT_SYS 0x04
#define FAT_VOL_ID 0x08
#define FAT_DIRECTORY 0x10
#define FAT_ARCHIVE 0x20
#define FAT_LONG_NAME 0x0F
static u16 bytes_per_sec = 0;
static u08 sec_per_clus = 0;
static u16 rsvd_sec_cnt = 0;
static u08 num_fats = 0;
static u16 tot_sech = 0;
static u16 tot_secl = 0;
static u16 root_clush = 0;
static u16 root_clusl = 0;
static u16 fat_sizeh = 0;
static u16 fat_sizel = 0;
// our offsets
static u16 first_part_sector = 0;
static u16 first_fat_sector = 0;
static u16 first_data_sectorl = 0;
// name of our volume
static u08 volume_id[8];
// the directiory that gets used if no other is specified
static DIR directory;
#ifdef LFN_SUPPORT
static u08 lfn_tmp[(LFN_MAX_BLOCK*13)+1];
#endif
/* is build in
void strcpy(u08 *to, u08 *from)
{ while(*from)
{ *to = *from;
to++;
from++;
}
};
*/
/*------------------ FAT LAYER --------------*/
// reads the mbr
// check for fat32 identifier
// finds the start of the first partition
u08 FAT_read_mbr(void)
{ // the number of bytes read
u16 length = 0;
u08 tmp;
// start reading the mbr
MMC_get_sec_start(0x00,0x00);
// get the data
while(length < 512)
{ length++;
// get next byte
tmp = MMC_get_sec_next();
// partition type
if(length == 451 && tmp != 0x0b)
while(1); // stop if no FAT32
// get the start sector of the first partition
if(length == 455) first_part_sector = tmp;
if(length == 456) first_part_sector += ((u16)tmp) << 8;
};
// stop reading from the mmc
MMC_get_sec_stop();
// FAB
return FAT_OK;
};
// scans the BPB in the first(0x00) sector of the first partition
void FAT_read_first_part_sector(void)
{ // the number of bytes read
u16 length = 0;
// start reading from the mmc
MMC_get_sec_start(0x00, first_part_sector);
while(length < 512)
{ // get the next byte
u08 tmp = MMC_get_sec_next();
// read fat data
switch(length)
{ case FAT_BYTES_PER_SECTOR:
// get upper byte;
bytes_per_sec = MMC_get_sec_next();
length++;
// assemble word
bytes_per_sec = (bytes_per_sec << 8) + tmp;
break;
case FAT_SEC_PER_CLUS:
sec_per_clus = tmp;
break;
case FAT_RSVD_SEC_CNT:
// get upper byte;
rsvd_sec_cnt = MMC_get_sec_next();
length++;
// assemble word
rsvd_sec_cnt = (rsvd_sec_cnt << 8) + tmp;
break;
case FAT_NUM_FATS:
num_fats = tmp;
break;
case FAT_TOTSEC:
// get second byte;
tot_secl = MMC_get_sec_next();
length++;
// assemble word
tot_secl = (tot_secl << 8) + tmp;
// get byte 3 and 4
tmp = MMC_get_sec_next();
length++;
// get second byte;
tot_sech = MMC_get_sec_next();
length++;
// assemble word
tot_sech = (tot_sech << 8) + tmp;
break;
case FAT_SIZE:
// get second byte;
fat_sizel = MMC_get_sec_next();
length++;
// assemble word
fat_sizel = (fat_sizel << 8) + tmp;
// get byte 3 and 4
tmp = MMC_get_sec_next();
length++;
// get second byte;
fat_sizeh = MMC_get_sec_next();
length++;
// assemble word
fat_sizeh = (fat_sizeh << 8) + tmp;
break;
case FAT_ROOT_CLUS:
// get second byte;
root_clusl = MMC_get_sec_next();
length++;
// assemble word
root_clusl = (root_clusl << 8) + tmp;
// get byte 3 and 4
tmp = MMC_get_sec_next();
length++;
// get second byte;
root_clush = MMC_get_sec_next();
length++;
// assemble word
root_clush = (root_clush << 8) + tmp;
break;
};
length++;
};
MMC_get_sec_stop();
};
// calc cluster to sectors
// by multiplying them with sec_per_clus
void cluster_to_sector(u16 *hiword, u16 *loword)
{ switch(sec_per_clus)
{ case 2:
*hiword = ((*hiword)<<1) + ((*loword)>>15);
*loword = ((*loword)<<1);
return;
case 4:
*hiword = ((*hiword)<<2) + ((*loword)>>14);
*loword = ((*loword)<<2);
return;
case 8:
*hiword = ((*hiword)<<3) + ((*loword)>>13);
*loword = ((*loword)<<3);
return;
case 16:
*hiword = ((*hiword)<<4) + ((*loword)>>12);
*loword = ((*loword)<<4);
return;
case 32:
*hiword = ((*hiword)<<5) + ((*loword)>>11);
*loword = ((*loword)<<5);
return;
case 64:
*hiword = ((*hiword)<<6) + ((*loword)>>10);
*loword = ((*loword)<<6);
return;
case 128:
*hiword = ((*hiword)<<7) + ((*loword)>>9);
*loword = ((*loword)<<7);
return;
}
}
// this function gets the addr in the data region for the next cluster of a file
void FAT_get_next_clus_addr(u16* clusterh, u16* clusterl)
{ // determine the sector that we need to read and which dword defines our next cluster address
u16 myh = *clusterh;
u16 myl = *clusterl;
u16 myoffset = *clusterl;
// turn clusters into byte address
myoffset = myoffset & 0x7f;
myl = (myl >> 7) + ((myh & 0x7f) << 9);
myh = myh >> 7;
myl += first_fat_sector;
if(myl < first_fat_sector) myh++;
// get the data
MMC_get_part_sec_start(myh, myl, myoffset << 2 ,4);
*clusterl = MMC_get_sec_next();
*clusterl += (MMC_get_sec_next() << 8);
*clusterh = MMC_get_sec_next();
*clusterh += (MMC_get_sec_next() << 8);
// fine
MMC_get_sec_stop();
};
void fat_init(void);
//
// 1.) reads the MBR
// gets start sector of first partition
// 2.) verifies start sector
// 3.) get BPB
// 4.) find fat start
// 5.) start reading fat
void FAT_startup(void)
{ u08 i;
// 1.) read MBR
if(FAT_read_mbr() != FAT_OK)
{ // some error occured
return;
}
// 2.) read BPB
FAT_read_first_part_sector();
// 3.) find fat start
first_fat_sector = first_part_sector + rsvd_sec_cnt;
first_data_sectorl = first_fat_sector + (num_fats * fat_sizel) - root_clusl*sec_per_clus;
for(i=0; i<8; i++)
{ volume_id[i] = 'X';
};
#ifdef LFN_SUPPORT
for(i=0; i < (LFN_MAX_BLOCK*12)+1; i++)
{ lfn_tmp[i]=0x00;
};
#endif
fat_init();
return;
};
/*------------------ FAT LAYER --------------*/
// compares a 11 byte block from the fat table with a 8 byte name and 3 byte extension.
// '*' is supported as a wildcard
bool fat_cmp_names(u08 *from_fat, u08 *name, u08 *extension)
{ u08 count = 0;
for(;count < 8; count++)
{ if(name[count] == '*')
{ count = 100;
}
else
{ if(name[count] != from_fat[count])
return false;
};
};
if(extension)
{ for(count=0; count < 3; count++)
{ if(extension[count] =='*')
{ count = 100;
}
else
{ if(extension[count] != from_fat[8+count])
return false;
};
};
};
return true;
};
// setup all the data needed by file i/o. gets called by FAT_startup
void fat_init(void)
{ directory.dir_currenth = root_clush;
directory.dir_currentl = root_clusl;
};
// takes a 32 byte long fat entry and opens the file contained within
void fat_load_file_ptr(u08 *fat_entry, FILE *stream)
{ u08 i;
stream->file_first_clusterl = (((u16)fat_entry[27])<<8) + (u16)fat_entry[26];
stream->file_first_clusterh = (((u16)fat_entry[21])<<8) + (u16)fat_entry[20];
stream->file_current_clusterl = stream->file_first_clusterl;
stream->file_current_clusterh = stream->file_first_clusterh;
stream->file_current_sector = 0;
stream->file_full_sizel = stream->file_sizel = (((u16)fat_entry[29])<<8) + fat_entry[28];
stream->file_full_sizeh = stream->file_sizeh = (((u16)fat_entry[31])<<8) + fat_entry[30];
stream->file_offset = 0x00;
for(i=0; i<11; i++)
{ stream->name[i] = fat_entry[i];
};
#ifdef LFN_SUPPORT
stream->lfn_name[0] = 0x00;
strcpy(stream->lfn_name, lfn_tmp);
#endif
};
// takes a 32 byte long fat entry and opens the dir contained within
void fat_load_dir_ptr(u08 *fat_entry, DIR *stream)
{ // get the dirposition
stream->dir_currentl = (((u16)fat_entry[27])<<8) + fat_entry[26];
stream->dir_currenth = (((u16)fat_entry[21])<<8) + fat_entry[20];
};
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -