From 1dff4b65f725c2174c65698e498b1d58d61e3968 Mon Sep 17 00:00:00 2001 From: Björn Stenberg Date: Fri, 26 Apr 2002 16:44:58 +0000 Subject: FAT update Added fat test code git-svn-id: svn://svn.rockbox.org/rockbox/trunk@254 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/fat.c | 570 +++++++------------------------------------- firmware/drivers/fat.h | 80 ++++--- firmware/test/fat/Makefile | 25 ++ firmware/test/fat/ata-sim.c | 52 ++++ firmware/test/fat/debug.c | 175 ++++++++++++++ firmware/test/fat/debug.h | 9 + 6 files changed, 399 insertions(+), 512 deletions(-) create mode 100644 firmware/test/fat/Makefile create mode 100644 firmware/test/fat/ata-sim.c create mode 100644 firmware/test/fat/debug.c create mode 100644 firmware/test/fat/debug.h diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c index 328428a941..a4cd77dc89 100644 --- a/firmware/drivers/fat.c +++ b/firmware/drivers/fat.c @@ -30,6 +30,12 @@ #include "fat.h" #include "ata.h" +#define BYTES2INT16(array,pos) \ + (array[pos] | (array[pos+1] << 8 )) +#define BYTES2INT32(array,pos) \ + (array[pos] | (array[pos+1] << 8 ) | \ + (array[pos+2] << 16 ) | (array[pos+3] << 24 )) + #define NUM_ROOT_DIR_ENTRIES 512 #define NUM_FATS 2 #define NUM_RESERVED_SECTORS 1 @@ -41,33 +47,6 @@ struct dsksz2secperclus unsigned int sec_per_cluster; }; -/* -** This is the table for FAT16 drives. NOTE that this table includes -** entries for disk sizes larger than 512 MB even though typically -** only the entries for disks < 512 MB in size are used. -** The way this table is accessed is to look for the first entry -** in the table for which the disk size is less than or equal -** to the DiskSize field in that table entry. For this table to -** work properly BPB_RsvdSecCnt must be 1, BPB_NumFATs -** must be 2, and BPB_RootEntCnt must be 512. Any of these values -** being different may require the first table entries DiskSize value -** to be changed otherwise the cluster count may be to low for FAT16. -*/ -struct dsksz2secperclus dsk_table_fat16 [] = -{ - { 8400, 0}, /* disks up to 4.1 MB, the 0 value for SecPerClusVal - trips an error */ - { 32680, 2}, /* disks up to 16 MB, 1k cluster */ - { 262144, 4}, /* disks up to 128 MB, 2k cluster */ - { 524288, 8}, /* disks up to 256 MB, 4k cluster */ - { 1048576, 16}, /* disks up to 512 MB, 8k cluster */ -/* The entries after this point are not used unless FAT16 is forced */ - { 2097152, 32}, /* disks up to 1 GB, 16k cluster */ - { 4194304, 64}, /* disks up to 2 GB, 32k cluster */ - { 0xFFFFFFFF, 0} /* any disk greater than 2GB, - 0 value for SecPerClusVal trips an error */ -}; - int fat_num_rootdir_sectors(struct bpb *bpb); int fat_first_sector_of_cluster(struct bpb *bpb, unsigned int cluster); int fat_get_fatsize(struct bpb* bpb); @@ -84,7 +63,6 @@ int fat_update_entry(struct bpb *bpb, int entry, unsigned int val); unsigned int fat_getcurrdostime(unsigned short *dosdate, unsigned short *dostime, unsigned char *dostenth); -int fat_create_root_dir(struct bpb *bpb); int fat_create_dos_name(unsigned char *name, unsigned char *newname); int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name); @@ -94,14 +72,10 @@ char current_directory[256] = "\\"; struct bpb *global_bpb; struct disk_info di; -extern int yyparse(void); - #ifdef TEST_FAT -void prompt(void) -{ - printf("C:%s>", current_directory); -} + +#include "debug.h" int main(int argc, char *argv[]) { @@ -110,27 +84,18 @@ int main(int argc, char *argv[]) memset(fat_cache, 0, sizeof(fat_cache)); memset(fat_cache_dirty, 0, sizeof(fat_cache_dirty)); - disk_init(NUM_BLOCKS); - di.num_sectors = NUM_BLOCKS; di.sec_per_track = 40; di.num_heads = 250; di.hidden_sectors = 0; - if(read_disk("diskdump.dmp") < 0) - { + if(ata_init()) printf("*** Warning! The disk is uninitialized\n"); - } else - { fat_get_bpb(&bpb); - } global_bpb = &bpb; - prompt(); - yyparse(); - - dump_disk("diskdump.dmp"); + dbg_console(&bpb); return 0; } #endif @@ -148,28 +113,6 @@ int fat_sec2cluster(struct bpb *bpb, unsigned int sec) return ((sec - first_sec) / bpb->bpb_secperclus) + 2; } -int fat_last_cluster_in_chain(struct bpb *bpb, unsigned int cluster) -{ - int iseof = 0; - - switch(bpb->fat_type) - { - case FATTYPE_FAT12: - if(cluster >= 0x0ff8) - iseof = 1; - break; - case FATTYPE_FAT16: - if(cluster >= 0xfff8) - iseof = 1; - break; - case FATTYPE_FAT32: - if(cluster >= 0x0ffffff8) - iseof = 1; - break; - } - return iseof; -} - int fat_cluster2sec(struct bpb *bpb, unsigned int cluster) { int max_cluster = (fat_get_totsec(bpb) - fat_first_data_sector(bpb)) / @@ -214,7 +157,7 @@ int fat_get_totsec(struct bpb* bpb) int fat_get_rootdir_sector(struct bpb *bpb) { - return bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fat_get_fatsize(bpb); + return bpb->bpb_rootclus; } int fat_first_data_sector(struct bpb* bpb) @@ -229,118 +172,6 @@ int fat_first_data_sector(struct bpb* bpb) return bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz + rootdirsectors; } -int fat_format(struct disk_info *di, char *vol_name) -{ - unsigned char buf[BLOCK_SIZE]; - struct bpb bpb; - unsigned int root_dir_sectors; - unsigned int tmp1, tmp2; - int sec_per_clus = 0; - int fat_size; - int i = 0; - int err; - - while(di->num_sectors > dsk_table_fat16[i].disk_size) - { - i++; - } - - sec_per_clus = dsk_table_fat16[i].sec_per_cluster; - - if(sec_per_clus == 0) - { - fprintf(stderr, "fat_format() - Bad disk size (%u)\n", - di->num_sectors); - return -1; - } - - /* First calculate how many sectors we need for - the root directory */ - root_dir_sectors = ((NUM_ROOT_DIR_ENTRIES * 32) + - (BLOCK_SIZE - 1)) / BLOCK_SIZE; - - /* Now calculate the FAT size */ - tmp1 = di->num_sectors - (NUM_RESERVED_SECTORS + root_dir_sectors); - tmp2 = (256 * sec_per_clus) + NUM_FATS; - - fat_size = (tmp1 + (tmp2 - 1)) / tmp2; - - /* Now create the BPB. We must be careful, so we really make - it little endian. */ - memset(buf, 0xff, BLOCK_SIZE); - - strncpy(&buf[BS_OEMNAME], "MSWIN4.1", 8); - buf[BPB_BYTSPERSEC] = BLOCK_SIZE & 0xff; - buf[BPB_BYTSPERSEC+1] = BLOCK_SIZE >> 8; - buf[BPB_SECPERCLUS] = sec_per_clus; - buf[BPB_RSVDSECCNT] = 1; - buf[BPB_RSVDSECCNT+1] = 0; - buf[BPB_NUMFATS] = 2; - buf[BPB_ROOTENTCNT] = NUM_ROOT_DIR_ENTRIES & 0xff; - buf[BPB_ROOTENTCNT+1] = NUM_ROOT_DIR_ENTRIES >> 8; - buf[BPB_TOTSEC16] = di->num_sectors & 0xff; - buf[BPB_TOTSEC16+1] = di->num_sectors >> 8; - buf[BPB_MEDIA] = 0xf0; - buf[BPB_FATSZ16] = fat_size & 0xff; - buf[BPB_FATSZ16+1] = fat_size >> 8; - buf[BPB_SECPERTRK] = di->sec_per_track & 0xff; - buf[BPB_SECPERTRK+1] = di->sec_per_track >> 8; - buf[BPB_NUMHEADS] = di->num_heads & 0xff; - buf[BPB_NUMHEADS+1] = di->num_heads >> 8; - buf[BPB_HIDDSEC] = di->hidden_sectors & 0xff; - buf[BPB_HIDDSEC+1] = (di->hidden_sectors >> 8) & 0xff; - buf[BPB_HIDDSEC+2] = (di->hidden_sectors >> 16) & 0xff; - buf[BPB_HIDDSEC+3] = (di->hidden_sectors >> 24) & 0xff; - buf[BPB_TOTSEC32] = 0; - buf[BPB_TOTSEC32+1] = 0; - buf[BPB_TOTSEC32+2] = 0; - buf[BPB_TOTSEC32+3] = 0; - - buf[BS_DRVNUM] = 0; - buf[BS_RESERVED1] = 0; - buf[BS_BOOTSIG] = 0x29; - buf[BS_VOLID] = 0x78; - buf[BS_VOLID+1] = 0x56; - buf[BS_VOLID+2] = 0x34; - buf[BS_VOLID+3] = 0x12; - memset(&buf[BS_VOLLAB], ' ', 11); - strncpy(&buf[BS_VOLLAB], vol_name, MIN(11, strlen(vol_name)); - strncpy(&buf[BS_FILSYSTYPE], "FAT16 ", 8); - - /* The final signature */ - buf[BPB_LAST_WORD] = 0x55; - buf[BPB_LAST_WORD+1] = 0xaa; - - /* Now write the sector to disk */ - err = ata_write_sectors(0,1,buf); - if(err) - { - fprintf(stderr, "fat_format() - Couldn't write BSB (error code %i)\n", - err); - return -1; - } - - if(fat_get_bpb(&bpb) < 0) - { - fprintf(stderr, "fat_format() - Couldn't read BPB\n"); - return -1; - } - - if(fat_create_fat(&bpb) < 0) - { - fprintf(stderr, "fat_format() - Couldn't create FAT\n"); - return -1; - } - - if(fat_create_root_dir(&bpb) < 0) - { - fprintf(stderr, "fat_format() - Couldn't write root dir sector\n"); - return -1; - } - - return 0; -} - int fat_get_bpb(struct bpb *bpb) { unsigned char buf[BLOCK_SIZE]; @@ -365,40 +196,34 @@ int fat_get_bpb(struct bpb *bpb) strncpy(bpb->bs_oemname, &buf[BS_OEMNAME], 8); bpb->bs_oemname[8] = 0; - bpb->bpb_bytspersec = buf[BPB_BYTSPERSEC] | (buf[BPB_BYTSPERSEC+1] << 8); + bpb->bpb_bytspersec = BYTES2INT16(buf,BPB_BYTSPERSEC); bpb->bpb_secperclus = buf[BPB_SECPERCLUS]; - bpb->bpb_rsvdseccnt = buf[BPB_RSVDSECCNT] | (buf[BPB_RSVDSECCNT+1] << 8); - bpb->bpb_numfats = buf[BPB_NUMFATS]; - bpb->bpb_rootentcnt = buf[BPB_ROOTENTCNT] | (buf[BPB_ROOTENTCNT+1] << 8); - bpb->bpb_totsec16 = buf[BPB_TOTSEC16] | (buf[BPB_TOTSEC16+1] << 8); - bpb->bpb_media = buf[BPB_MEDIA]; - bpb->bpb_fatsz16 = buf[BPB_FATSZ16] | (buf[BPB_FATSZ16+1] << 8); - bpb->bpb_secpertrk = buf[BPB_SECPERTRK] | (buf[BPB_SECPERTRK+1] << 8); - bpb->bpb_numheads = buf[BPB_NUMHEADS] | (buf[BPB_NUMHEADS+1] << 8); - bpb->bpb_hiddsec = buf[BPB_HIDDSEC] | (buf[BPB_HIDDSEC+1] << 8) | - (buf[BPB_HIDDSEC+2] << 16) | (buf[BPB_HIDDSEC+3] << 24); - bpb->bpb_totsec32 = buf[BPB_TOTSEC32] | (buf[BPB_TOTSEC32+1] << 8) | - (buf[BPB_TOTSEC32+2] << 16) | (buf[BPB_TOTSEC32+3] << 24); - - bpb->bs_drvnum = buf[BS_DRVNUM]; - bpb->bs_bootsig = buf[BS_BOOTSIG]; + bpb->bpb_rsvdseccnt = BYTES2INT16(buf,BPB_RSVDSECCNT); + bpb->bpb_numfats = buf[BPB_NUMFATS]; + bpb->bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT); + bpb->bpb_totsec16 = BYTES2INT16(buf,BPB_TOTSEC16); + bpb->bpb_media = buf[BPB_MEDIA]; + bpb->bpb_fatsz16 = BYTES2INT16(buf,BPB_FATSZ16); + bpb->bpb_secpertrk = BYTES2INT16(buf,BPB_SECPERTRK); + bpb->bpb_numheads = BYTES2INT16(buf,BPB_NUMHEADS); + bpb->bpb_hiddsec = BYTES2INT32(buf,BPB_HIDDSEC); + bpb->bpb_totsec32 = BYTES2INT32(buf,BPB_TOTSEC32); + bpb->bs_drvnum = buf[BS_DRVNUM]; + bpb->bs_bootsig = buf[BS_BOOTSIG]; + bpb->bpb_fatsz32 = BYTES2INT32(buf,BPB_FATSZ32); + bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD); + if(bpb->bs_bootsig == 0x29) { - bpb->bs_volid = buf[BS_VOLID] | (buf[BS_VOLID+1] << 8) | - (buf[BS_VOLID+2] << 16) | (buf[BS_VOLID+3] << 24); + bpb->bs_volid = BYTES2INT32(buf,BS_VOLID); strncpy(bpb->bs_vollab, &buf[BS_VOLLAB], 11); strncpy(bpb->bs_filsystype, &buf[BS_FILSYSTYPE], 8); } - bpb->bpb_fatsz32 = (buf[BPB_FATSZ32] + (buf[BPB_FATSZ32+1] << 8)) | - (buf[BPB_FATSZ32+2] << 16) | (buf[BPB_FATSZ32+3] << 24); - - bpb->last_word = buf[BPB_LAST_WORD] | (buf[BPB_LAST_WORD+1] << 8); - /* Determine FAT type */ fatsz = fat_get_fatsize(bpb); - if(bpb->bpb_totsec16 != 0) + if (bpb->bpb_totsec16 != 0) totsec = bpb->bpb_totsec16; else totsec = bpb->bpb_totsec32; @@ -408,23 +233,30 @@ int fat_get_bpb(struct bpb *bpb) rootdirsectors); countofclusters = datasec / bpb->bpb_secperclus; - if(countofclusters < 4085) - { - bpb->fat_type = FATTYPE_FAT12; - } - else - { - if(countofclusters < 65525) - { - bpb->fat_type = FATTYPE_FAT16; - } - else - { - bpb->fat_type = FATTYPE_FAT32; - } + + /* Determining FAT type: + + This is the "proper way" to do it: + + if (countofclusters < 4085) + fat12 + else + if (countofclusters < 65525) + fat16 + else + fat32 + */ + + /* + This is the "real world way" to do it + (since not all FAT32 partitions have >65524 clusters) + */ + if ( bpb->bpb_fatsz16 ) { + printf("This is not FAT32. Go away!\n"); + return -1; } - if(fat_bpb_is_sane(bpb) < 0) + if (fat_bpb_is_sane(bpb) < 0) { fprintf(stderr, "fat_get_bpb() - BPB is not sane\n"); return -1; @@ -435,12 +267,6 @@ int fat_get_bpb(struct bpb *bpb) int fat_bpb_is_sane(struct bpb *bpb) { - if(bpb->fat_type == FATTYPE_FAT32) - { - fprintf(stderr, "fat_bpb_is_sane() - Error: FAT32 not supported\n"); - return -1; - } - if(bpb->bpb_bytspersec != 512) { fprintf(stderr, @@ -504,75 +330,6 @@ int fat_bpb_is_sane(struct bpb *bpb) return 0; } -int fat_create_fat(struct bpb* bpb) -{ - unsigned char *sec; - int i; - int secnum = 0; - int fatsz; - - if(fat_bpb_is_sane(bpb) < 0) - { - fprintf(stderr, "fat_create_fat() - BPB is not sane\n"); - return -1; - } - - if(bpb->bpb_fatsz16 != 0) - fatsz = bpb->bpb_fatsz16; - else - fatsz = bpb->bpb_fatsz32; - - sec = fat_cache_fat_sector(bpb, secnum); - if(!sec) - { - fprintf(stderr, "fat_create_fat() - Couldn't cache fat sector" - " (%d)\n", secnum); - return -1; - } - - fat_cache_dirty[secnum] = 1; - - /* First entry should have the media type in the - low byte and the rest of the bits set to 1. - The second should be the EOC mark. */ - memset(sec, 0, BLOCK_SIZE); - sec[0] = bpb->bpb_media; - if(bpb->fat_type == FATTYPE_FAT12) - { - sec[1] = 0xff; - sec[2] = 0xff; - } - if(bpb->fat_type == FATTYPE_FAT16) - { - sec[0] = bpb->bpb_media; - sec[1] = 0xff; - sec[2] = 0xff; - sec[3] = 0xff; - } - secnum++; - - for(i = 0; i < fatsz - 1;i++) - { - sec = fat_cache_fat_sector(bpb, secnum); - if(!sec) - { - fprintf(stderr, "fat_create_fat() - Couldn't cache fat sector" - " (%d)\n", i); - return -1; - } - fat_cache_dirty[secnum] = 1; - secnum++; - memset(sec, 0, BLOCK_SIZE); - } - - if(fat_flush_fat(bpb) < 0) - { - fprintf(stderr, "fat_create_fat() - Couldn't flush fat\n"); - return -1; - } - return 0; -} - int fat_dbg_read_block(char *name, unsigned char *buf) { FILE *f; @@ -628,7 +385,6 @@ unsigned char *fat_cache_fat_sector(struct bpb *bpb, int secnum) int fat_update_entry(struct bpb *bpb, int entry, unsigned int val) { unsigned char *sec; - unsigned char *sec2; int fatsz; int fatoffset; int thisfatsecnum; @@ -636,18 +392,7 @@ int fat_update_entry(struct bpb *bpb, int entry, unsigned int val) unsigned int tmp; fatsz = fat_get_fatsize(bpb); - - if(bpb->fat_type == FATTYPE_FAT12) - { - fatoffset = entry + (entry / 2); - } - else - { - if(bpb->fat_type == FATTYPE_FAT16) - fatoffset = entry * 2; - else - fatoffset = entry * 4; - } + fatoffset = entry * 4; thisfatsecnum = fatoffset / bpb->bpb_bytspersec; thisfatentoffset = fatoffset % bpb->bpb_bytspersec; @@ -662,55 +407,16 @@ int fat_update_entry(struct bpb *bpb, int entry, unsigned int val) fat_cache_dirty[thisfatsecnum] = 1; - switch(bpb->fat_type) - { - case FATTYPE_FAT12: - if(thisfatentoffset == bpb->bpb_bytspersec - 1) - { - /* This entry spans a sector boundary. Take care */ - sec2 = fat_cache_fat_sector(bpb, thisfatsecnum + 1); - /* Load the sector if it is not cached */ - if(!sec2) - { - fprintf(stderr, "fat_update_entry() - Could not " - "cache sector %d\n", - thisfatsecnum + 1); - return -1; - } - fat_cache_dirty[thisfatsecnum + 1] = 1; - } - else - { - if(entry & 1) /* Odd entry number? */ - { - tmp = sec[thisfatentoffset] & 0xf0; - sec[thisfatentoffset] = tmp | (val & 0x0f); - sec[thisfatentoffset+1] = (val >> 4) & 0xff; - } - else - { - sec[thisfatentoffset] = val & 0xff; - tmp = sec[thisfatentoffset+1] & 0x0f; - sec[thisfatentoffset+1] = tmp | ((val >> 4) & 0xf0); - } - } - break; - case FATTYPE_FAT16: - *(unsigned short *)(&sec[thisfatentoffset]) = val; - break; - case FATTYPE_FAT32: - tmp = *(unsigned short *)(&sec[thisfatentoffset]) & 0xf000000; - val = tmp | (val & 0x0fffffff); - *(unsigned short *)(&sec[thisfatentoffset]) = val; - break; - } + tmp = *(unsigned short *)(&sec[thisfatentoffset]) & 0xf000000; + val = tmp | (val & 0x0fffffff); + *(unsigned short *)(&sec[thisfatentoffset]) = val; + return 0; } int fat_read_entry(struct bpb *bpb, int entry) { unsigned char *sec; - unsigned char *sec2; int fatsz; int fatoffset; int thisfatsecnum; @@ -718,18 +424,7 @@ int fat_read_entry(struct bpb *bpb, int entry) int val = -1; fatsz = fat_get_fatsize(bpb); - - if(bpb->fat_type == FATTYPE_FAT12) - { - fatoffset = entry + (entry / 2); - } - else - { - if(bpb->fat_type == FATTYPE_FAT16) - fatoffset = entry * 2; - else - fatoffset = entry * 4; - } + fatoffset = entry * 4; thisfatsecnum = fatoffset / bpb->bpb_bytspersec; thisfatentoffset = fatoffset % bpb->bpb_bytspersec; @@ -742,43 +437,7 @@ int fat_read_entry(struct bpb *bpb, int entry) return -1; } - switch(bpb->fat_type) - { - case FATTYPE_FAT12: - if(thisfatentoffset == bpb->bpb_bytspersec - 1) - { - /* This entry spans a sector boundary. Take care */ - sec2 = fat_cache_fat_sector(bpb, thisfatsecnum + 1); - /* Load the sector if it is not cached */ - if(!sec2) - { - fprintf(stderr, "fat_update_entry() - Could not " - "cache sector %d\n", - thisfatsecnum + 1); - return -1; - } - } - else - { - if(entry & 1) /* Odd entry number? */ - { - val = (sec[thisfatentoffset] & 0x0f) | - (sec[thisfatentoffset+1] << 4); - } - else - { - val = (sec[thisfatentoffset] & 0xff) | - ((sec[thisfatentoffset+1] & 0x0f) << 8); - } - } - break; - case FATTYPE_FAT16: - val = *(unsigned short *)(&sec[thisfatentoffset]); - break; - case FATTYPE_FAT32: - val = *(unsigned int *)(&sec[thisfatentoffset]); - break; - } + val = *(unsigned int *)(&sec[thisfatentoffset]); return val; } @@ -843,67 +502,12 @@ unsigned int fat_getcurrdostime(unsigned short *dosdate, return 0; } -int fat_create_root_dir(struct bpb *bpb) -{ - unsigned char buf[BLOCK_SIZE]; - int fatsz; - int sec; - int res; - int i; - unsigned short dosdate; - unsigned short dostime; - unsigned char dostenth; - int num_root_sectors; - - fatsz = fat_get_fatsize(bpb); - - sec = bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz; - - memset(buf, 0, sizeof(buf)); - - strncpy(&buf[FATDIR_NAME], bpb->bs_vollab, 11); - buf[FATDIR_ATTR] = FAT_ATTR_VOLUME_ID; - buf[FATDIR_NTRES] = 0; - - fat_getcurrdostime(&dosdate, &dostime, &dostenth); - buf[FATDIR_WRTDATE] = dosdate & 0xff; - buf[FATDIR_WRTDATE+1] = dosdate >> 8; - buf[FATDIR_WRTTIME] = dostime & 0xff; - buf[FATDIR_WRTTIME+1] = dostime >> 8; - - printf("Writing rootdir to sector %d...\n", sec); - - res = ata_write_sectors(sec,1,buf); - if(res) - { - fprintf(stderr, "fat_create_root_dir() - Couldn't write sector (%d)\n", - sec); - return -1; - } - - printf("Clearing the rest of the root dir.\n"); - sec++; - num_root_sectors = bpb->bpb_rootentcnt * 32 / bpb->bpb_bytspersec; - memset(buf, 0, BLOCK_SIZE); - - for(i = 1;i < num_root_sectors;i++) - { - if(ata_write_sectors(sec++,1,buf)) - { - fprintf(stderr, "fat_create_root_dir() - " - " Couldn't write sector (%d)\n", sec); - return -1; - } - } - - return 0; -} - int fat_get_next_cluster(struct bpb *bpb, unsigned int cluster) { int next_cluster = fat_read_entry(bpb, cluster); - if(fat_last_cluster_in_chain(bpb, next_cluster)) + /* is this last cluster in chain? */ + if ( next_cluster >= 0x0ffffff8 ) return 0; else return next_cluster; @@ -1198,22 +802,26 @@ int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name) return err; } -void fat_fill_direntry(struct fat_direntry *de, char *buf) +int fat_parse_direntry(struct fat_direntry *de, char *buf) { - memset(de, 0, sizeof(struct fat_direntry)); + /* is this a long filename entry? */ + if ( ( buf[FATDIR_ATTR] & FAT_ATTR_LONG_NAME_MASK ) == + FAT_ATTR_LONG_NAME ) + { + return 0; + } - strncpy(de->name, &buf[FATDIR_NAME], 11); + memset(de, 0, sizeof(struct fat_direntry)); de->attr = buf[FATDIR_ATTR]; de->crttimetenth = buf[FATDIR_CRTTIMETENTH]; - de->crtdate = buf[FATDIR_CRTDATE] | (buf[FATDIR_CRTDATE+1] << 8); - de->crttime = buf[FATDIR_CRTTIME] | (buf[FATDIR_CRTTIME+1] << 8); - de->wrtdate = buf[FATDIR_WRTDATE] | (buf[FATDIR_WRTDATE+1] << 8); - de->wrttime = buf[FATDIR_WRTTIME] | (buf[FATDIR_WRTTIME+1] << 8); - - de->filesize = buf[FATDIR_FILESIZE] | - (buf[FATDIR_FILESIZE+1] << 8) | - (buf[FATDIR_FILESIZE+2] << 16) | - (buf[FATDIR_FILESIZE+3] << 24); + de->crtdate = BYTES2INT16(buf,FATDIR_CRTDATE); + de->crttime = BYTES2INT16(buf,FATDIR_CRTTIME); + de->wrtdate = BYTES2INT16(buf,FATDIR_WRTDATE); + de->wrttime = BYTES2INT16(buf,FATDIR_WRTTIME); + de->filesize = BYTES2INT32(buf,FATDIR_FILESIZE); + strncpy(de->name, &buf[FATDIR_NAME], 11); + + return 1; } int fat_opendir(struct bpb *bpb, struct fat_dirent *ent, unsigned int currdir) @@ -1246,8 +854,9 @@ int fat_opendir(struct bpb *bpb, struct fat_dirent *ent, unsigned int currdir) return 0; } -int fat_getnext(struct bpb *bpb, struct fat_dirent *ent, - struct fat_direntry *entry) +int fat_getnext(struct bpb *bpb, + struct fat_dirent *ent, + struct fat_direntry *entry) { int done = 0; int i; @@ -1261,18 +870,17 @@ int fat_getnext(struct bpb *bpb, struct fat_dirent *ent, { firstbyte = ent->cached_buf[i*32]; if(firstbyte == 0xe5) - { continue; - } - if(firstbyte == 0) - { + if(firstbyte == 0) { + printf("Firstbyte == 0\n"); return -1; } - fat_fill_direntry(entry, &ent->cached_buf[i*32]); - done = 1; - break; + if ( fat_parse_direntry(entry, &ent->cached_buf[i*32]) ) { + done = 1; + break; + } } /* Next sector? */ @@ -1284,9 +892,13 @@ int fat_getnext(struct bpb *bpb, struct fat_dirent *ent, /* Do we need to advance one cluster? */ if(ent->num_sec >= bpb->bpb_secperclus) { + int cluster = fat_sec2cluster(bpb, ent->cached_sec); + if ( cluster < 0 ) { + printf("sec2cluster failed\n"); + return -1; + } ent->num_sec = 0; - ent->cached_sec = fat_get_next_cluster( - bpb, fat_sec2cluster(bpb, ent->cached_sec)); + ent->cached_sec = fat_get_next_cluster( bpb, cluster ); if(!ent->cached_sec) { printf("End of cluster chain.\n"); diff --git a/firmware/drivers/fat.h b/firmware/drivers/fat.h index f1dc8dc5a0..99b40ac284 100644 --- a/firmware/drivers/fat.h +++ b/firmware/drivers/fat.h @@ -20,6 +20,8 @@ #ifndef FAT_H #define FAT_H +#define BLOCK_SIZE 512 + #define FATTYPE_FAT12 0 #define FATTYPE_FAT16 1 #define FATTYPE_FAT32 2 @@ -50,37 +52,42 @@ #define BPB_LAST_WORD 510 -#define MIN(a,b) (((a) < (b))?(a):(b))) +#define MIN(a,b) (((a) < (b))?(a):(b)) struct bpb { - char bs_oemname[9]; /* OEM string, ending with \0 */ - int bpb_bytspersec; /* Bytes per sectory, typically 512 */ - int bpb_secperclus; /* Sectors per cluster */ - int bpb_rsvdseccnt; /* Number of reserved sectors */ - int bpb_numfats; /* Number of FAT structures, typically 2 */ - int bpb_rootentcnt; /* Number of dir entries in the root */ - int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */ - int bpb_media; /* Media type (typically 0xf0 or 0xf8) */ - int bpb_fatsz16; /* Number of used sectors per FAT structure */ - int bpb_secpertrk; /* Number of sectors per track */ - int bpb_numheads; /* Number of heads */ - int bpb_hiddsec; /* Hidden sectors before the volume */ - unsigned int bpb_totsec32; /* Number of sectors on the volume - (new 32-bit) */ - /**** FAT12/16 specific *****/ - int bs_drvnum; /* Drive number */ - int bs_bootsig; /* Is 0x29 if the following 3 fields are valid */ - unsigned int bs_volid; /* Volume ID */ - char bs_vollab[12]; /* Volume label, 11 chars plus \0 */ - char bs_filsystype[9]; /* File system type, 8 chars plus \0 */ - - /**** FAT32 specific *****/ - int bpb_fatsz32; - - int last_word; /* Must be 0xaa55 */ - - int fat_type; /* What type of FAT is this? */ + char bs_oemname[9]; /* OEM string, ending with \0 */ + int bpb_bytspersec; /* Bytes per sectory, typically 512 */ + int bpb_secperclus; /* Sectors per cluster */ + int bpb_rsvdseccnt; /* Number of reserved sectors */ + int bpb_numfats; /* Number of FAT structures, typically 2 */ + int bpb_rootentcnt; /* Number of dir entries in the root */ + int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */ + int bpb_media; /* Media type (typically 0xf0 or 0xf8) */ + int bpb_fatsz16; /* Number of used sectors per FAT structure */ + int bpb_secpertrk; /* Number of sectors per track */ + int bpb_numheads; /* Number of heads */ + int bpb_hiddsec; /* Hidden sectors before the volume */ + unsigned int bpb_totsec32; /* Number of sectors on the volume + (new 32-bit) */ + /**** FAT12/16 specific *****/ + int bs_drvnum; /* Drive number */ + int bs_bootsig; /* Is 0x29 if the following 3 fields are valid */ + unsigned int bs_volid; /* Volume ID */ + char bs_vollab[12]; /* Volume label, 11 chars plus \0 */ + char bs_filsystype[9]; /* File system type, 8 chars plus \0 */ + + /**** FAT32 specific *****/ + int bpb_fatsz32; + int bpb_extflags; + int bpb_fsver; + int bpb_rootclus; + int bpb_fsinfo; + int bpb_bkbootsec; + + /* variables for internal use */ + int fat_type; /* FAT12, FAT16 or FAT32 */ + int last_word; /* must be 0xAA55 */ }; #define FAT_ATTR_READ_ONLY 0x01 @@ -91,6 +98,9 @@ struct bpb #define FAT_ATTR_ARCHIVE 0x20 #define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \ FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID) +#define FAT_ATTR_LONG_NAME_MASK (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \ + FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID | \ + FAT_ATTR_DIRECTORY | FAT_ATTR_ARCHIVE ) #define FATDIR_NAME 0 @@ -145,10 +155,14 @@ struct fat_dirent char cached_buf[BLOCK_SIZE]; }; -int fat_format(struct disk_info *di, char *vol_name); -int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name); -int fat_opendir(struct bpb *bpb, struct fat_dirent *ent, unsigned int currdir); -int fat_getnext(struct bpb *bpb, struct fat_dirent *ent, - struct fat_direntry *entry); +extern int fat_create_file(struct bpb *bpb, + unsigned int currdir, + char *name); +extern int fat_opendir(struct bpb *bpb, + struct fat_dirent *ent, + unsigned int currdir); +extern int fat_getnext(struct bpb *bpb, + struct fat_dirent *ent, + struct fat_direntry *entry); #endif diff --git a/firmware/test/fat/Makefile b/firmware/test/fat/Makefile new file mode 100644 index 0000000000..8b60aba99c --- /dev/null +++ b/firmware/test/fat/Makefile @@ -0,0 +1,25 @@ +DRIVERS = ../../drivers + +CFLAGS = -g -Wall -DTEST_FAT -I$(DRIVERS) -I. + +TARGET = fat + +$(TARGET): fat.o ata-sim.o debug.o + gcc -g -o fat $+ -lfl + +fat.o: $(DRIVERS)/fat.c $(DRIVERS)/fat.h $(DRIVERS)/ata.h + $(CC) $(CFLAGS) -c $< -o $@ + +ata-sim.o: ata-sim.c $(DRIVERS)/ata.h + +debug.o: debug.c debug.h $(DRIVERS)/ata.h + +clean: + rm -f *.o $(TARGET) + rm -f *~ + rm -f cmd.tab.h lex.yy.c cmd.tab.c + rm -f core + +tar: + rm -f $(TARGET).tar + tar cvf $(TARGET).tar -C .. fat diff --git a/firmware/test/fat/ata-sim.c b/firmware/test/fat/ata-sim.c new file mode 100644 index 0000000000..d8c28d9467 --- /dev/null +++ b/firmware/test/fat/ata-sim.c @@ -0,0 +1,52 @@ +#include +#include +#include + +#include "ata.h" + +#define BLOCK_SIZE 512 + +static FILE* file; + +int ata_read_sectors(unsigned long start, unsigned char count, void* buf) +{ + if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) { + perror("fseek"); + return -1; + } + if(!fread(buf,BLOCK_SIZE,count,file)) { + printf("Failed reading %d blocks starting at block %ld\n",count,start); + perror("fread"); + return -1; + } + return 0; +} + +int ata_write_sectors(unsigned long start, unsigned char count, void* buf) +{ + if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) { + perror("fseek"); + return -1; + } + if(!fwrite(buf,BLOCK_SIZE,count,file)) { + perror("fwrite"); + return -1; + } + return 0; +} + +int ata_init(void) +{ + /* check disk size */ + file=fopen("disk.img","r+"); + if(!file) { + fprintf(stderr, "read_disk() - Could not find \"disk.img\"\n"); + return -1; + } + return 0; +} + +void ata_exit(void) +{ + fclose(file); +} diff --git a/firmware/test/fat/debug.c b/firmware/test/fat/debug.c new file mode 100644 index 0000000000..046a67e06c --- /dev/null +++ b/firmware/test/fat/debug.c @@ -0,0 +1,175 @@ +#include +#include +#include +#include "fat.h" +#include "ata.h" +#include "debug.h" + +void dbg_dump_sector(int sec) +{ + unsigned char buf[512]; + + ata_read_sectors(sec,1,buf); + printf("---< Sector %d >-----------------------------------------\n", sec); + dbg_dump_buffer(buf); +} + +void dbg_dump_buffer(unsigned char *buf) +{ + int i, j; + unsigned char c; + unsigned char ascii[33]; + + for(i = 0;i < 512/32;i++) + { + for(j = 0;j < 32;j++) + { + c = buf[i*32+j]; + + printf("%02x ", c); + if(c < 32 || c > 127) + { + ascii[j] = '.'; + } + else + { + ascii[j] = c; + } + } + + ascii[j] = 0; + printf("%s\n", ascii); + } +} + +void dbg_print_bpb(struct bpb *bpb) +{ + printf("bpb_oemname = \"%s\"\n", bpb->bs_oemname); + printf("bpb_bytspersec = %d\n", bpb->bpb_bytspersec); + printf("bpb_secperclus = %d\n", bpb->bpb_secperclus); + printf("bpb_rsvdseccnt = %d\n", bpb->bpb_rsvdseccnt); + printf("bpb_numfats = %d\n", bpb->bpb_numfats); + printf("bpb_rootentcnt = %d\n", bpb->bpb_rootentcnt); + printf("bpb_totsec16 = %d\n", bpb->bpb_totsec16); + printf("bpb_media = %02x\n", bpb->bpb_media); + printf("bpb_fatsz16 = %d\n", bpb->bpb_fatsz16); + printf("bpb_secpertrk = %d\n", bpb->bpb_secpertrk); + printf("bpb_numheads = %d\n", bpb->bpb_numheads); + printf("bpb_hiddsec = %u\n", bpb->bpb_hiddsec); + printf("bpb_totsec32 = %u\n", bpb->bpb_totsec32); + + printf("bs_drvnum = %d\n", bpb->bs_drvnum); + printf("bs_bootsig = %02x\n", bpb->bs_bootsig); + if(bpb->bs_bootsig == 0x29) + { + printf("bs_volid = %xl\n", bpb->bs_volid); + printf("bs_vollab = \"%s\"\n", bpb->bs_vollab); + printf("bs_filsystype = \"%s\"\n", bpb->bs_filsystype); + } + + printf("bpb_fatsz32 = %u\n", bpb->bpb_fatsz32); + printf("last_word = %04x\n", bpb->last_word); + + switch(bpb->fat_type) + { + case FATTYPE_FAT12: + printf("fat_type = FAT12\n"); + break; + case FATTYPE_FAT16: + printf("fat_type = FAT16\n"); + break; + case FATTYPE_FAT32: + printf("fat_type = FAT32\n"); + break; + default: + printf("fat_type = UNKNOWN (%d)\n", bpb->fat_type); + break; + } +} + +void dbg_dir(struct bpb *bpb, int currdir) +{ + struct fat_dirent dent; + struct fat_direntry de; + + if(fat_opendir(bpb, &dent, currdir) >= 0) + { + while(fat_getnext(bpb, &dent, &de) >= 0) + { + printf("%s\n", de.name); + } + } + else + { + fprintf(stderr, "Could not read dir on cluster %d\n", currdir); + } +} + +extern char current_directory[]; +int last_secnum = 0; + +void dbg_prompt(void) +{ + printf("C:%s> ", current_directory); +} + +void dbg_console(struct bpb* bpb) +{ + char cmd[32] = ""; + char last_cmd[32] = ""; + int quit = 0; + char *s; + int secnum; + + while(!quit) + { + dbg_prompt(); + if(fgets(cmd, sizeof(cmd) - 1, stdin)) + { + if(strlen(cmd) == 1) /* empty command? */ + { + strcpy(cmd, last_cmd); + } + + /* Get the first token */ + s = strtok(cmd, " \n"); + if(s) + { + if(!strcasecmp(s, "dir")) + { + secnum = 0; + if((s = strtok(NULL, " \n"))) + { + secnum = atoi(s); + } + dbg_dir(bpb, secnum); + continue; + } + + if(!strcasecmp(s, "ds")) + { + /* Remember the command */ + strcpy(last_cmd, s); + + if((s = strtok(NULL, " \n"))) + { + last_secnum = atoi(s); + } + else + { + last_secnum++; + } + printf("secnum: %d\n", last_secnum); + dbg_dump_sector(last_secnum); + continue; + } + + if(!strcasecmp(s, "exit") || + !strcasecmp(s, "x")) + { + quit = 1; + } + } + } + } +} diff --git a/firmware/test/fat/debug.h b/firmware/test/fat/debug.h new file mode 100644 index 0000000000..ff786ab2b1 --- /dev/null +++ b/firmware/test/fat/debug.h @@ -0,0 +1,9 @@ +#ifndef DEBUG_H +#define DEBUG_H + +void dbg_dump_sector(int sec); +void dbg_dump_buffer(unsigned char *buf); +void dbg_print_bpb(struct bpb *bpb); +void dbg_console(struct bpb *bpb); + +#endif -- cgit v1.2.3