From 23fc923bde033d2abffa29651f3dff921abcaed7 Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Sun, 7 Sep 2008 17:24:14 +0000 Subject: ZVM: * Optimize MiniFS handling * Add basic CFS handling (doesn't work yet) * Remove hacky stuff in disk.c git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18438 a1c6a512-1295-4272-9138-f99709370657 --- .../arm/tms320dm320/creative-zvm/ata-creativezvm.c | 337 ++++++++++++++++++--- 1 file changed, 300 insertions(+), 37 deletions(-) (limited to 'firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c') diff --git a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c index 1732c5d2c4..5f325a5e54 100644 --- a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c +++ b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c @@ -31,7 +31,10 @@ #include "ata.h" #include "string.h" -void sleep_ms(int ms) +#undef ata_read_sectors +#undef ata_write_sectors + +static void sleep_ms(int ms) { sleep(ms*HZ/1000); } @@ -99,7 +102,7 @@ bool ata_is_coldstart(void) void ata_device_init(void) { IO_INTC_EINT1 |= INTR_EINT1_EXT2; /* enable GIO2 interrupt */ - //TODO: mimic OF inits... + /* TODO: mimic OF inits... */ return; } @@ -114,38 +117,308 @@ void GIO2(void) /* --------------------------------------------------------------------------- - Creative File Systems parsing code + CreativeFileSystem parsing/handling code --------------------------------------------------------------------------- */ +#define VFAT_SECTOR_SIZE ( (1*1024*1024*1024)/0x8000 ) /* 1GB array requires 80kB of RAM */ + +extern int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf); +extern int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf); + struct main_header { char mblk[4]; - unsigned char sector_size[4]; - unsigned char disk_size[8]; + unsigned int sector_size; + long long disk_size; struct partition_header { - unsigned char end[4]; - unsigned char start[4]; + unsigned long end; + unsigned long start; char name[8]; } partitions[31]; }; +struct cfs_header +{ + unsigned int unk; + unsigned int unk2; + unsigned int sector_size; + unsigned int unk4; + unsigned int unk5; + char identifier[4]; + unsigned int first_inode; + unsigned int unk8; + unsigned int unk9; + unsigned int unk10; + unsigned int unk11; +}; + +struct cfs_inode +{ + unsigned char magic[4]; + unsigned int number; + unsigned int parent; + unsigned int unk; + unsigned int type; + unsigned int created_time; + unsigned int lastmodified_time; + unsigned int unk2; + unsigned int first_class_chain[12]; + unsigned int unk3; + unsigned int unk4; + unsigned int second_class_chain_first_cluster; + unsigned int unk9; + unsigned int unk10; + unsigned int second_class_chain_second_cluster; + unsigned int unk11; + unsigned int unk12; + unsigned int unk13; + unsigned int filesize; + unsigned int serial_number; + unsigned int number_of_metadata_records; +}; + +struct cfs_direntry +{ + unsigned char identifier[4]; + unsigned int unk; + unsigned int items; + unsigned int unk2; + unsigned char maxlen[2]; + unsigned char padding[202]; + /* struct cfs_direntry_item _items[items]; */ +}; +struct cfs_direntry_item +{ + unsigned int inode_number; + unsigned short strlen; + unsigned short bytesperchar; + char string[32]; +}; + +static bool cfs_inited = false; +static unsigned long cfs_start; +static unsigned long sectors[VFAT_SECTOR_SIZE]; + +#define CFS_START ( ((hdr->partitions[1].start*hdr->sector_size) & ~0xFFFF) + 0x10000 ) +#define CFS_CLUSTER2CLUSTER(x) ( CFS_START+((x)-1)*64 ) + +/* Limited version of UCS -> ASCII */ +static char* ucs2letostring(unsigned char* s) +{ + static char res[256]; + int i; + + for(i=0; (s[i] == 0 && s[i+1] == 0); i++) + res[i] = s[i*2]; + + return (char*)&res; +} + +static void cfs_init(void) +{ + struct main_header *hdr; + struct cfs_header *cfs; + struct cfs_inode *root_inode, *vfat_inode, *inode; + struct cfs_direntry *root_direntry, *vfat_direntry; + struct cfs_direntry_item *root_direntry_items, *vfat_direntry_items; + unsigned int i, j, k, vfat_inode_nr=0, vfat_inodes_nr[10], vfat_sector_count; + unsigned char sector[512]; + static unsigned int vfat_data[2][0x8000]; + static unsigned char sector2[0x8000]; + + if(cfs_inited) + return; + + /* Read MBLK */ + _ata_read_sectors(0, 1, §or); + hdr = (struct main_header*)§or; + + //printf("CFS is at 0x%x", CFS_START); + + /* Read CFS header */ + _ata_read_sectors(CFS_START/512, 64, §or2); + cfs = (struct cfs_header*)§or2; + + //printf("First inode = %d", cfs->first_inode); + + /* Read root inode */ + _ata_read_sectors(CFS_CLUSTER2CLUSTER(cfs->first_inode), 64, §or2); + root_inode = (struct cfs_inode*)§or2; + + /* Read root inode's first sector */ + _ata_read_sectors(CFS_CLUSTER2CLUSTER(root_inode->first_class_chain[0]), 64, §or2); + root_direntry = (struct cfs_direntry*)§or2; + root_direntry_items = (struct cfs_direntry_item*)(§or2+sizeof(struct cfs_direntry)); + + /* Search VFAT inode */ + for(i=0; i < root_direntry->items; i++) + { + //printf(" * [%s] at 0x%x\n", ucs2letostring(&root_direntry_items[i].string[0]), root_direntry_items[i].inode_number); + if(strcmp(ucs2letostring(&root_direntry_items[i].string[0]), "VFAT") == 0) + vfat_inode_nr = root_direntry_items[i].inode_number; + } + + /* Read VFAT inode */ + _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_inode_nr), 64, §or2); + vfat_inode = (struct cfs_inode*)§or2; + + /* Read VFAT inode's first sector */ + _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_inode->first_class_chain[0]), 64, §or2); + vfat_direntry = (struct cfs_direntry*)§or2; + vfat_direntry_items = (struct cfs_direntry_item*)(§or2+sizeof(struct cfs_direntry)); + + /* Search for VFAT's subinodes */ + for(i=0; i < vfat_direntry->items; i++) + { + //printf(" * [%s] at 0x%x\n", ucs2letostring(&vfat_direntry_items[i].string[0]), vfat_direntry_items[i].inode_number); + if(i > 0) + vfat_inodes_nr[i-1] = vfat_direntry_items[i].inode_number; + } + + /* Read all data sectors' addresses in memory */ + vfat_sector_count = 0; + memset(§ors, 0, VFAT_SECTOR_SIZE*sizeof(unsigned int)); + for(i=0; vfat_inodes_nr[i] != 0; i++) + { + _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_inodes_nr[i]), 1, §or); + inode = (struct cfs_inode*)§or; + + /* Read second & third class chain */ + _ata_read_sectors(CFS_CLUSTER2CLUSTER(inode->second_class_chain_first_cluster), 64, &vfat_data[0]); + _ata_read_sectors(CFS_CLUSTER2CLUSTER(inode->second_class_chain_second_cluster), 64, &vfat_data[1]); + + /* First class chain */ + for(j=0; j<12; j++) + { + if( (inode->first_class_chain[j] & 0xFFFF) != 0xFFFF && + inode->first_class_chain[j] != 0 + ) + sectors[vfat_sector_count++] = inode->first_class_chain[j]; + } + + /* Second class chain */ + for(j=0; j<0x8000/4; j++) + { + if( (vfat_data[0][j] & 0xFFFF) != 0xFFFF && + vfat_data[0][j] != 0 + ) + sectors[vfat_sector_count++] = vfat_data[0][j]; + } + + /* Third class chain */ + for(j=0; j<0x8000/4; j++) + { + if( (vfat_data[1][j] & 0xFFFF) != 0xFFFF && + vfat_data[1][j] != 0 + ) + { + memset(&vfat_data[0], 0, 0x8000*sizeof(unsigned int)); + + /* Read third class subchain(s) */ + _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_data[1][j]), 64, &vfat_data[0]); + + for(k=0; k<0x8000/4; k++) + { + if( (vfat_data[0][k] & 0xFFFF) != 0xFFFF && + vfat_data[0][k] != 0 + ) + sectors[vfat_sector_count++] = vfat_data[0][k]; + } + } + } + } + + //printf("Sector count: %d 0x%x", vfat_sector_count, vfat_sector_count); + + cfs_inited = true; +} + +static inline unsigned long map_sector(unsigned long sector) +{ + /* + * Sector mapping: start of CFS + FAT_SECTOR2CFS_SECTOR(sector) + missing part + * FAT works with sectors of 0x200 bytes, CFS with sectors of 0x8000 bytes. + */ + return cfs_start+sectors[sector/64]*64+sector%64; +} + +int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) +{ + if(!cfs_inited) + cfs_init(); + + /* Check if count is lesser than or equal to 1 native CFS sector */ + if(count <= 64) + return _ata_read_sectors(IF_MV2(drive,) map_sector(start), count, buf); + else + { + int i, ret; + unsigned char* dest = (unsigned char*)buf; + + /* Read sectors in parts of 0x8000 */ + for(i=0; i= 64 ? 64 : count-i), (void*)dest); + if(ret != 0) + return ret; + + dest += (count-i >= 64 ? 0x8000 : (count-i)*512); + } + + return ret; + } +} + +int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf) +{ + if(!cfs_inited) + cfs_init(); + + /* Check if count is lesser than or equal to 1 native CFS sector */ + if(count <= 64) + return _ata_write_sectors(IF_MV2(drive,) map_sector(start), count, buf); + else + { + int i, ret; + unsigned char* dest = (unsigned char*)buf; + + /* Read sectors in parts of 0x8000 */ + for(i=0; i= 64 ? 64 : count-i), (const void*)dest); + if(ret != 0) + return ret; + + dest += (count-i >= 64 ? 0x8000 : (count-i)*512); + } + + return ret; + } +} + +/* + --------------------------------------------------------------------------- + MiniFileSystem parsing code + --------------------------------------------------------------------------- + */ + struct minifs_file { char name[0x10]; - unsigned char unk[4]; - unsigned char size[4]; - unsigned char chain1[4]; - unsigned char chain2[4]; + unsigned int unk; + unsigned long size; + unsigned int chain1; + unsigned int chain2; }; struct minifs_chain { - unsigned char unknown[4]; - unsigned char chain[2*0x27FE]; - unsigned char unknown2[4]; - unsigned char length[4]; + unsigned int unknown; + unsigned short chain[0x27FE]; + unsigned int unknown2; + unsigned long length; }; @@ -160,16 +433,6 @@ struct minifs_chain #define CLUSTER_CHAIN_CHAIN 0x0002 -static unsigned short le2int16(unsigned char* buf) -{ - return (buf[1] << 8) | buf[0]; -} - -static unsigned int le2int32(unsigned char* buf) -{ - return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; -} - int load_minifs_file(char* filename, unsigned char* location) { struct main_header *hdr; @@ -180,13 +443,13 @@ int load_minifs_file(char* filename, unsigned char* location) unsigned char sector[512]; static unsigned char chain_data[42*512]; /* stack overflow if not static */ - /* Reading MBLK */ - ata_read_sectors(0, 1, §or); + /* Read MBLK */ + _ata_read_sectors(0, 1, §or); hdr = (struct main_header*)§or; - /* Reading directory listing */ -#define CLUSTER2SECTOR(x) ( (le2int32(hdr->partitions[0].start) + (x)*8) ) - ata_read_sectors(CLUSTER2SECTOR(DIR_START), 8, &files); + /* Read directory listing */ +#define CLUSTER2SECTOR(x) ( (hdr->partitions[0].start + (x)*8) ) + _ata_read_sectors(CLUSTER2SECTOR(DIR_START), 8, &files); for(i=0; i<127; i++) { @@ -200,17 +463,17 @@ int load_minifs_file(char* filename, unsigned char* location) #define GET_CHAIN(x) ( CLUSTER2SECTOR(CLUSTER_CHAIN_CHAIN)*512 + (x)*CLUSTER_CHAIN_SIZE ) #define FILE2SECTOR(x) ( CLUSTER2SECTOR(DATASPACE_START + (x)) ) - /* Reading chain list */ - ata_read_sectors(GET_CHAIN(le2int32(files[found].chain1))/512, 41, &chain_data[0]); + /* Read chain list */ + _ata_read_sectors(GET_CHAIN(files[found].chain1)/512, 41, &chain_data[0]); - chain = (struct minifs_chain*)&chain_data[GET_CHAIN(le2int32(files[found].chain1))%512]; + chain = (struct minifs_chain*)&chain_data[GET_CHAIN(files[found].chain1)%512]; - /* Copying data */ - for(i=0; ilength); i++) + /* Copy data */ + for(i=0; ilength; i++) { - ata_read_sectors(FILE2SECTOR(le2int16(&chain->chain[i*2])), 8, location); + _ata_read_sectors(FILE2SECTOR(chain->chain[i]), 8, location); location += 0x1000; } - return le2int32(files[found].size); + return files[found].size; } -- cgit v1.2.3