diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/common/disk.c | 43 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c | 337 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/creative-zvm/ata-target.h | 24 |
3 files changed, 317 insertions, 87 deletions
diff --git a/firmware/common/disk.c b/firmware/common/disk.c index f6b836cca8..4add5b99df 100644 --- a/firmware/common/disk.c +++ b/firmware/common/disk.c @@ -81,7 +81,6 @@ struct partinfo* disk_init(IF_MV_NONVOID(int drive)) #endif ata_read_sectors(IF_MV2(drive,) 0,1, §or); -#ifndef CREATIVE_ZVx /* check that the boot sector is initialized */ if ( (sector[510] != 0x55) || (sector[511] != 0xaa)) { @@ -104,46 +103,6 @@ struct partinfo* disk_init(IF_MV_NONVOID(int drive)) /* not handled yet */ } } -#else - struct partition_struct - { - unsigned int end; - unsigned int start; - char name[8]; - }; - struct hdd_struct - { - unsigned char MBLK[4]; - int sector_size; - long long total_disk_size; - struct partition_struct partitions[4]; - }; - struct hdd_struct* hdd_struct = (struct hdd_struct*)sector; - - if(hdd_struct->MBLK[0] != 0x4B || - hdd_struct->MBLK[1] != 0x4C || - hdd_struct->MBLK[2] != 0x42 || - hdd_struct->MBLK[3] != 0x4D) /* 0x4B4C424D = KLBM */ - { - DEBUGF("Bad boot sector signature\n"); - return NULL; - } - else - { - /* parse partitions */ - for ( i=0; i<4; i++ ) { - if(hdd_struct->partitions[i].name[0] != 0) - { - pinfo[i].type = ( strcmp(hdd_struct->partitions[i].name, "cfs") == 0 ? PARTITION_TYPE_FAT32_LBA : 0); - pinfo[i].start = hdd_struct->partitions[i].start; - pinfo[i].size = (hdd_struct->partitions[i].end - hdd_struct->partitions[i].start); - - DEBUGF("Part%d: Type %02x, start: %08lx size: %08lx\n", - i,pinfo[i].type,pinfo[i].start,pinfo[i].size); - } - } - } -#endif return pinfo; } @@ -200,7 +159,7 @@ int disk_mount(int drive) { return 0; } -#if defined(TOSHIBA_GIGABEAT_S) || defined(CREATIVE_ZVx) +#if defined(TOSHIBA_GIGABEAT_S) int i = 1; /* For the Gigabeat S, we mount the second partition */ #else int i = 0; 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<count; i+=64)
+ {
+ ret = _ata_read_sectors(IF_MV2(drive,) map_sector(start+i), (count-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<count; i+=64)
+ {
+ ret = _ata_write_sectors(IF_MV2(drive,) map_sector(start+i), (count-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; i<le2int32(chain->length); i++)
+ /* Copy data */
+ for(i=0; i<chain->length; 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;
}
diff --git a/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h b/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h index 6e5699e887..ba877a1496 100644 --- a/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h +++ b/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h @@ -22,6 +22,8 @@ #ifndef ATA_TARGET_H #define ATA_TARGET_H +#include "ata.h" + /* DMA optimized reading and writing */ #define ATA_OPTIMIZED_READING #define ATA_OPTIMIZED_WRITING @@ -33,6 +35,12 @@ void copy_read_sectors(const unsigned char* buf, int wordcount); void copy_write_sectors(const unsigned char* buf, int wordcount); +/* Nasty hack, but Creative is nasty... */ +#define ata_read_sectors _ata_read_sectors +#define ata_write_sectors _ata_write_sectors +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); + /* General purpose memory region #1 */ #define ATA_IOBASE 0x50FEE000 #define ATA_DATA (*((volatile unsigned short*)(ATA_IOBASE))) @@ -52,15 +60,15 @@ void copy_write_sectors(const unsigned char* buf, int wordcount); #define STATUS_ERR 0x01 #define ERROR_ABRT 0x04 -#define WRITE_PATTERN1 0xa5 -#define WRITE_PATTERN2 0x5a -#define WRITE_PATTERN3 0xaa -#define WRITE_PATTERN4 0x55 +#define WRITE_PATTERN1 0xa5 +#define WRITE_PATTERN2 0x5a +#define WRITE_PATTERN3 0xaa +#define WRITE_PATTERN4 0x55 -#define READ_PATTERN1 0xa5 -#define READ_PATTERN2 0x5a -#define READ_PATTERN3 0xaa -#define READ_PATTERN4 0x55 +#define READ_PATTERN1 0xa5 +#define READ_PATTERN2 0x5a +#define READ_PATTERN3 0xaa +#define READ_PATTERN4 0x55 #define READ_PATTERN1_MASK 0xff #define READ_PATTERN2_MASK 0xff |