summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/common/disk.c43
-rw-r--r--firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c337
-rw-r--r--firmware/target/arm/tms320dm320/creative-zvm/ata-target.h24
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, &sector);
-#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, &sector);
+ hdr = (struct main_header*)&sector;
+
+ //printf("CFS is at 0x%x", CFS_START);
+
+ /* Read CFS header */
+ _ata_read_sectors(CFS_START/512, 64, &sector2);
+ cfs = (struct cfs_header*)&sector2;
+
+ //printf("First inode = %d", cfs->first_inode);
+
+ /* Read root inode */
+ _ata_read_sectors(CFS_CLUSTER2CLUSTER(cfs->first_inode), 64, &sector2);
+ root_inode = (struct cfs_inode*)&sector2;
+
+ /* Read root inode's first sector */
+ _ata_read_sectors(CFS_CLUSTER2CLUSTER(root_inode->first_class_chain[0]), 64, &sector2);
+ root_direntry = (struct cfs_direntry*)&sector2;
+ root_direntry_items = (struct cfs_direntry_item*)(&sector2+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, &sector2);
+ vfat_inode = (struct cfs_inode*)&sector2;
+
+ /* Read VFAT inode's first sector */
+ _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_inode->first_class_chain[0]), 64, &sector2);
+ vfat_direntry = (struct cfs_direntry*)&sector2;
+ vfat_direntry_items = (struct cfs_direntry_item*)(&sector2+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(&sectors, 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, &sector);
+ inode = (struct cfs_inode*)&sector;
+
+ /* 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, &sector);
+ /* Read MBLK */
+ _ata_read_sectors(0, 1, &sector);
hdr = (struct main_header*)&sector;
- /* 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