void prtn_set_addr(byte* bootSec, dword partition_addr) { int resSecs; //# of reserved sectors byte numFATs; //# of FATs word max_root_entries; /* max# of root dir entries */ word secs_per_FAT; byte secs_per_clus; secs_per_clus = bootSec[0x0d]; resSecs = ((bootSec[0x0f]<<8)&0xFF00)|(bootSec[0x0e]&0x00FF); max_root_entries = ((bootSec[0x12]<<8)&0xFF00)|(bootSec[0x11]&0x00FF); numFATs = bootSec[0x10]; secs_per_FAT = ((bootSec[0x17]<<8)&0xFF00)|(bootSec[0x16]&0x00FF); prtn.bytes_per_sec = ((bootSec[0x0c]<<8)&0xFF00)|(bootSec[0x0b]&0x00FF); prtn.root_dir_addr = partition_addr + ((long)resSecs + (long)secs_per_FAT*(long)numFATs)*(long)(prtn.bytes_per_sec); prtn.FAT_addr = partition_addr + (long)resSecs*(long)(prtn.bytes_per_sec); prtn.data_addr = prtn.root_dir_addr + (max_root_entries*32); prtn.clus_size = prtn.bytes_per_sec * secs_per_clus; prtn.FAT_size = prtn.bytes_per_sec * secs_per_FAT; prtn.root_dir_size = max_root_entries * 16; #if DEBUG pmsg("Bytes per sector: "); disword_dec(prtn.bytes_per_sec); pmsg("\r\n"); pmsg("Number of reserved sectors: "); disword_dec(resSecs); pmsg("\r\n"); pmsg("root dir at: 0x"); disdword(prtn.root_dir_addr); pmsg("\r\n"); pmsg("FAT at: 0x"); disdword(prtn.FAT_addr); pmsg("\r\n"); pmsg("Data starts at: 0x"); disdword(prtn.data_addr); pmsg("\r\n"); #endif }
byte read_block(byte* buf,dword addr) { int i; byte c; byte r1; if (addr % 512 != 0) { #if DEBUG pmsg("read_block: Address 0x"); disdword(addr); pmsg("is not aligned to a 512 byte block!\r\n"); #endif return 0; } #if DEBUG pmsg("Reading block at address 0x"); disdword(addr); pmsg("\r\n"); #endif r1=CMD(17,addr); for (i=0;i<50;i++) // wait until the data is found { if (r1==0x00) break; r1 = SPI_Byte(0xFF); } if (r1!=0x00) { #if DEBUG pmsg("Read block timed out!\r\n"); #endif return 0; } c = SPI_Byte(0xFF); while (c!=0xFE) { c=SPI_Byte(0xFF); } // wait for the "data follows" code for (i=0;i<512;i++) { *(buf++)=SPI_Byte(0xFF); } c=SPI_Byte(0xFF); c=SPI_Byte(0xFF); // dummy bytes to clear any queues return 1; }
// returns address of first empty root dir entry dword get_empty_dir_entry(byte* buf) { byte i,j; byte b; for (i=0;i<32;i++) { b = read_block(buf, prtn.root_dir_addr + i*512); for(j=0;j<16;j++) { if(buf[j*32] == 0x00 || buf[j*32] == 0xE5) { #if DEBUG pmsg("found empty direntry at addr: 0x"); disdword(prtn.root_dir_addr + i*512 + j*32); pmsg("\r\n"); #endif return (prtn.root_dir_addr + i*512 + j*32); } } } #if DEBUG pmsg("Failed to find empty directory entry!\r\n"); #endif return 0; }
byte create_dir_entry(dir_entry_t* de, char* filename, byte fn_length, byte* buf) { dword dir_entry_addr; memmove(de->filename, filename, fn_length); de->attributes = NEW_FILE_ATTR; de->filesize = 0; memset(de->unused_attr, 0, 14); dir_entry_addr = get_empty_dir_entry(buf); #if DEBUG pmsg("get_direntry returned: 0x"); disdword(dir_entry_addr); pmsg("\r\n"); #endif if (!dir_entry_addr) { #if DEBUG pmsg("Couldn't find empty direntry!\r\n"); #endif return 0; } de->entry_addr = dir_entry_addr; // when direntry is allocated cluster is not yet entered de->first_cluster = 0x0000; return 1; }
byte write_block(byte* data, dword addr) { byte c; short i; if (addr % 512 != 0) { #if DEBUG pmsg("write_block: Address 0x"); disdword(addr); pmsg("is not aligned to a 512 byte block!\r\n"); #endif return 0; } #if DEBUG pmsg("Writing block at address 0x"); disdword(addr); pmsg("\r\n"); #endif if (CMD(24,addr) != 0) { #if DEBUG pmsg("Failed to write block!\r\n"); #endif return 0; } c=SPI_Byte(0xFF); c=SPI_Byte(0xFF); c=SPI_Byte(0xFE); // lead in to actual data for (i=0;i<BLOCKSIZE;i++) c=SPI_Byte(data[i]); c=SPI_Byte(0xFF); c=SPI_Byte(0xFF); // dummy before response recieved c=SPI_Byte(0xFF); c&=0x1F; // bit mask for write error codes // see http://elm-chan.org/docs/mmc/mmc_e.html if (c!=0x05) { #if DEBUG pmsg("Failed to write block!\r\n"); #endif return 0; } while (SPI_Byte(0xFF)!=0xFF); // block until write finished return 1; }
byte initFAT(byte* buf) { byte i; dword partition_addr; i = read_block(buf,0); if(!i){ #if DEBUG pmsg("read timed out"); #endif return 0; } if (buf[PARTENTRY1 + 0x04] != 0x04 && buf[PARTENTRY1 + 0x04] != 0x06) { #if DEBUG pmsg("drive is not FAT16!\r\n"); #endif return 0; } partition_addr = ((dword)buf[PARTENTRY1 + 0x08] | (dword)buf[PARTENTRY1 + 0x09] << 8 | (dword)buf[PARTENTRY1 + 0x0a] << 16 | (dword)buf[PARTENTRY1 + 0x0b] << 24) * 512; #if DEBUG pmsg("partition_addr is: "); disdword(partition_addr); pmsg("\r\n"); #endif if (!read_block(buf, partition_addr)) { #if DEBUG pmsg("couldn't read start of partition!\r\n"); #endif return 0; } prtn_set_addr(buf, partition_addr); return 1; }