diff --git a/desmume/src/MMU.c b/desmume/src/MMU.c index cbc18a6b3..d676967c1 100644 --- a/desmume/src/MMU.c +++ b/desmume/src/MMU.c @@ -27,7 +27,7 @@ #include "debug.h" #include "NDSSystem.h" -#include "windows/cflash.h" +#include "cflash.h" #include "nds/interrupts.h" #include "nds/video.h" diff --git a/desmume/src/Makefile.am b/desmume/src/Makefile.am index 09235dbcd..c7b118abf 100644 --- a/desmume/src/Makefile.am +++ b/desmume/src/Makefile.am @@ -12,6 +12,6 @@ libdesmume_a_SOURCES = \ mc.c mc.h \ arm9/GPU.c arm9/GPU.h \ arm9/ARM9.c arm9/ARM9.h \ - windows/cflash.c windows/cflash.h fs.h \ + cflash.c cflash.h fs.h \ saves.c saves.h libdesmume_a_LIBADD = fs-$(desmume_arch).$(OBJEXT) diff --git a/desmume/src/cflash.c b/desmume/src/cflash.c new file mode 100644 index 000000000..453833ab5 --- /dev/null +++ b/desmume/src/cflash.c @@ -0,0 +1,689 @@ +/* + CFLASH.C + CompactFlash/FAT emulation routines for DeSmuME + /Mic, 2006 + + Portability note: Uses some Win32 API calls, e.g. FindNextFile, + which would have to be replaced for other operating systems. + + Logical memory layout: + + ---------------------- + | MBR | + ---------------------- + | FAT | + ---------------------- + | Root entries | + ---------------------- + | Subdirectories | + ---------------------- + | File data | + ---------------------- + +*/ + +#include "fs.h" +#include "cflash.h" +#include "NDSSystem.h" +#include +#include +#include + + +#define SECPERFAT 128 +#define SECPERCLUS 16 +#define MAXFILES 32768 +#define SECRESV 2 +#define NUMSECTORS 0x80000 +#define NUMCLUSTERS (NUMSECTORS/SECPERCLUS) +#define BYTESPERCLUS (512*SECPERCLUS) +#define DIRENTSPERCLUS ((BYTESPERCLUS)/32) + + +u16 cf_reg_data,cf_reg_err,cf_reg_sec,cf_reg_lba1,cf_reg_lba2, + cf_reg_lba3,cf_reg_lba4,cf_reg_cmd,cf_reg_sts; +unsigned int CF_REG_DATA,CF_REG_ERR,CF_REG_SEC,CF_REG_LBA1,CF_REG_LBA2, + CF_REG_LBA3,CF_REG_LBA4,CF_REG_CMD,CF_REG_STS; + +BOOT_RECORD MBR; +DIR_ENT *files,*dirEntries,**dirEntryPtr; +FILE_INFO *fileLink,*dirEntryLink; +u32 currLBA; +u32 filesysFAT,filesysRootDir,filesysData; +u16 FAT16[SECPERFAT*256]; +u16 numExtraEntries[SECPERFAT*256]; +DIR_ENT *extraDirEntries[SECPERFAT*256]; +int numFiles,fileLevel,maxLevel,dirNum,numRootFiles; +int *dirEntriesInCluster,clusterNum, + firstDirEntCluster,lastDirEntCluster, + lastFileDataCluster; +char *sRomPath; +int activeDirEnt=-1; +u32 bufferStart; +u32 fileStartLBA,fileEndLBA; +u16 freadBuffer[256]; +u32 dwBytesRead; +FILE * hFile; +char fpath[255+1]; +BOOL cflashDeviceEnabled = FALSE; +char buffer[256]; +u32 dummy; + + +int lfn_checksum() { + int i; + u8 chk; + + chk = 0; + for (i=0; i < 11; i++) { + chk = ((chk & 1) ? 0x80 : 0) + (chk >> 1) + (i < 8 ? files[numFiles].name[i] : files[numFiles].ext[i - 8]); + } + return chk; +} + + +const int lfnPos[13] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; + + +/* Add a DIR_ENT for the files */ +void add_file(char *fname, FsEntry * entry) { + int i,j,k,n; + u8 chk; + char *p; + + if (numFiles < MAXFILES-1) { + if (strcmp(fname,"..") != 0) { + for (i=strlen(fname)-1; i>=0; i--) + if (fname[i]=='.') break; + if ((i==0)&&(strcmp(fname,".")==0)) i = 1; + if (i<0) i = strlen(fname); + for (j=0; j=strlen(fname)) break; + files[numFiles].ext[j] = fname[j+i+1]; + } + for (; j<3; j++) + files[numFiles].ext[j] = 0x20; + + fileLink[maxLevel * ((fileLevel>0)?1:0)].filesInDir += 1; + + // See if LFN entries need to be added + if (strlen(entry->cAlternateFileName)>0) { + chk = lfn_checksum(); + k = (strlen(entry->cFileName)/13) + (((strlen(entry->cFileName)%13)!=0)?1:0); + numFiles += k; + + fileLink[maxLevel * ((fileLevel>0)?1:0)].filesInDir += k; + + n = 0; + j = 13; + for (i=0; icFileName); i++) { + if (j == 13) { + n++; + p = (char*)&files[numFiles-n].name[0]; + fileLink[numFiles-n].parent = maxLevel * ((fileLevel>0)?1:0); + p[0] = n; + ((DIR_ENT*)p)->attrib = ATTRIB_LFN; + p[0xD] = chk; + j = 0; + } + *(p + lfnPos[j]) = entry->cFileName[i]; + *(p + lfnPos[j]+1) = 0; + j++; + } + for (; j<13; j++) { + *(p + lfnPos[j]) = entry->cFileName[i]; + *(p + lfnPos[j]+1) = 0; + } + p[0] |= 0x40; // END + for (i=strlen(fname)-1; i>=0; i--) + if (fname[i]=='.') break; + if ((i==0)&&(strcmp(fname,".")==0)) i = 1; + if (i<0) i = strlen(fname); + for (j=0; j=strlen(fname)) break; + files[numFiles].ext[j] = fname[j+i+1]; + } + for (; j<3; j++) + files[numFiles].ext[j] = 0x20; + } + + //files[numFiles].fileSize = entry->nFileSizeLow; + files[numFiles].fileSize = 0; + + if (entry->flags & FS_IS_DIR) { + if (strcmp(fname,".")==0) + fileLink[numFiles].level = maxLevel; + else + fileLink[numFiles].level = maxLevel+1; + files[numFiles].attrib = ATTRIB_DIR; + } else { + files[numFiles].attrib = 0; + } + + fileLink[numFiles].parent = maxLevel * ((fileLevel>0)?1:0); + + numFiles++; + } else if (fileLevel > 0) { + fileLink[maxLevel * ((fileLevel>0)?1:0)].filesInDir += 1; + strncpy((char*)&files[numFiles].name[0],".. ",8); + strncpy((char*)&files[numFiles].ext[0]," ",3); + fileLink[numFiles].parent = maxLevel * ((fileLevel>0)?1:0); + files[numFiles].attrib = 0x10; + numFiles++; + } + } +} + + +/* List all files and subdirectories recursively */ +void list_files(char *fpath) { + void * hFind; + FsEntry entry; + char DirSpec[255 + 1],SubDir[255+1],fnameu[256]; + u32 dwError; + char *fname; + int i,j; + + fileLevel++; + maxLevel++; + + strncpy(DirSpec, fpath, strlen(fpath)+1); + + hFind = FsReadFirst(DirSpec, &entry); + + if (hFind == NULL) { + return; + } else { + fname = (strlen(entry.cAlternateFileName)>0)?entry.cAlternateFileName:entry.cFileName; + strcpy(fnameu,fname); + //strupr(fnameu); + add_file(fnameu,&entry); + + while (FsReadNext(hFind, &entry) != 0) { + fname = (strlen(entry.cAlternateFileName)>0)?entry.cAlternateFileName:entry.cFileName; + strcpy(fnameu,fname); + //strupr(fnameu); + + add_file(fnameu,&entry); + + if (numFiles==MAXFILES-1) break; + + if ((entry.flags & FS_IS_DIR)&& + (fname[0] != '.')) { + //sprintf(SubDir,"%s\\%s",fpath,fname); + sprintf(SubDir,"%s%c%s",fpath,FS_SEPARATOR,fname); + list_files(SubDir); + } + } + + dwError = FsError(); + FsClose(hFind); + if (dwError != FS_ERR_NO_MORE_FILES) { + return; + } + } + if (numFiles < MAXFILES) { + fileLink[numFiles].parent = maxLevel * ((fileLevel>0)?1:0); + files[numFiles++].name[0] = 0; + } + fileLevel--; +} + + + + + + +/* Set up the MBR, FAT and DIR_ENTs */ +BOOL cflash_build_fat() { + int i,j,k,l, + clust,baseCluster,numClusters, + clusterNum2,rootCluster; + + numFiles = 0; + fileLevel = -1; + maxLevel = -1; + + sRomPath = szRomPath; // From MMU.cpp + files = (DIR_ENT *) malloc(MAXFILES*sizeof(DIR_ENT)); + fileLink = (FILE_INFO *) malloc(MAXFILES*sizeof(FILE_INFO)); + if ((files == NULL) || (fileLink == NULL)) + return FALSE; + + for (i=0; i>8; + clust += l; + numClusters += l; + } + } else { + dirEntries[k-1].startCluster = clusterNum; + } + } + if (i==0) numRootFiles++; + dirEntriesInCluster[clusterNum]++; + if (dirEntriesInCluster[clusterNum]==256) { + clusterNum++; + } + } + } + clusterNum = clusterNum2 + ((fileLink[i].filesInDir)>>8) + 1; + numClusters++; + } + + // Free the file indexing buffer + free(files); + free(fileLink); + + // Set up the MBR + MBR.bytesPerSector = 512; + MBR.numFATs = 1; + strcpy((char*)&MBR.OEMName[0],"DESMUM"); + strcpy((char*)&MBR.fat16.fileSysType[0],"FAT16 "); + MBR.reservedSectors = SECRESV; + MBR.numSectors = 524288; + MBR.numSectorsSmall = 0; + MBR.sectorsPerCluster = SECPERCLUS; + MBR.sectorsPerFAT = SECPERFAT; + MBR.rootEntries = 512; + MBR.fat16.signature = 0xAA55; + MBR.mediaDesc = 1; + + filesysFAT = 0 + MBR.reservedSectors; + filesysRootDir = filesysFAT + (MBR.numFATs * MBR.sectorsPerFAT); + filesysData = filesysRootDir + ((MBR.rootEntries * sizeof(DIR_ENT)) / 512); + + // Set up the cluster values for all subdirectories + clust = filesysData / SECPERCLUS; + firstDirEntCluster = clust; + for (i=1; i rootCluster) + dirEntries[i].startCluster += clust-rootCluster; + } + } + lastDirEntCluster = clust+numClusters-1; + + // Set up the cluster values for all files + clust += numClusters; //clusterNum; + for (i=0; i 0) { + if (dirEntries[i].startCluster+j < MAXFILES) + FAT16[dirEntries[i].startCluster+j] = dirEntries[i].startCluster+j+1; + j++; + l -= (512*16); + } + if ((dirEntries[i].attrib & ATTRIB_DIR)==0) { + if (dirEntries[i].startCluster+j < MAXFILES) + FAT16[dirEntries[i].startCluster+j] = 0xFFFF; + } + k = dirEntries[i].startCluster+j; + } + } + + for (i=(filesysData/SECPERCLUS); iname[i] == ' ') break; + out[i] = pd->name[i]; + } + if ((pd->attrib & 0x10)==0) { + out[i++] = '.'; + for (j=0; j<3; j++) { + if (pd->ext[j] == ' ') break; + out[i++] = pd->ext[j]; + } + } + out[i] = '\0'; +} + + + +/* Resolve the path of a files by working backwards through the directory entries */ +void resolve_path(int dirent) { + int i; + char dirname[128]; + + while (dirEntryLink[dirent].parent > 0) { + for (i=0; i= bufferStart + 512)) { + //SetFilePointer(hFile,offset,NULL,FILE_BEGIN); + fseek(hFile, offset, SEEK_SET); + //ReadFile(hFile,&freadBuffer,512,&dwBytesRead,NULL); + fread(&freadBuffer, 1, 512, hFile); + bufferStart = offset; + } + + return freadBuffer[(offset-bufferStart)>>1]; + } + if (activeDirEnt != -1) + //CloseHandle(hFile); + fclose(hFile); + + strcpy(fpath,sRomPath); + strcat(fpath,"\\"); + + resolve_path(dirent); + + fatstring_to_asciiz(dirent,fname,NULL); + strcat(fpath,fname); + + hFile = fopen(fpath, "w"); + if (!hFile) + return 0; + fread(&freadBuffer, 1, 512, hFile); + + bufferStart = offset; + activeDirEnt = dirent; + fileStartLBA = (dirEntries[dirent].startCluster*512*SECPERCLUS); + fileEndLBA = fileStartLBA + dirEntries[dirent].fileSize; + + return freadBuffer[(offset-bufferStart)>>1]; +} + +/* Read from one of the CF device registers */ +unsigned int cflash_read(unsigned int address) { + unsigned char *p; + u16 s; + int i; + u32 cluster,cluster2,cluster3,fileLBA; + + //wsprintf(buffer,"Reading from %08X\n",address); + //WriteConsole(hStdOut,buffer,lstrlen(buffer),(u32*)&dummy,NULL); + + if (address == CF_REG_STS) { + s = cf_reg_sts; + return s; + + } else if (address == CF_REG_DATA) { + cluster = (currLBA / (512 * SECPERCLUS)); + cluster2 = (((currLBA/512) - filesysData) / SECPERCLUS) + 2; + + if (cf_reg_cmd == 0x20) { + // Reading from the MBR + if (currLBA < 512) { + p = (unsigned char*)&MBR; + s = *(u16 *)(p + currLBA); + + // Reading the FAT + } else if ((currLBA >= filesysFAT*512) && (currLBA < filesysRootDir*512)) { + p = (unsigned char*)&FAT16[0]; + s = *(u16 *)(p + (currLBA-filesysFAT*512)); + + // Reading directory entries + } else if ((currLBA >= filesysRootDir*512) && + (cluster <= lastDirEntCluster)) { + cluster3 = ((currLBA - (SECRESV * 512)) / (512 * SECPERCLUS)); + i = (currLBA-(((cluster3-(filesysRootDir/SECPERCLUS))*SECPERCLUS+filesysRootDir)*512)); //(currLBA - cluster*BYTESPERCLUS); + if (i < (dirEntriesInCluster[cluster3]*32)) { + + p = (unsigned char*)dirEntryPtr[cluster3]; + s = *(u16 *)(p + i); + } else { + i /= 32; + i -= dirEntriesInCluster[cluster3]; + if ((i>=0)&&(i lastDirEntCluster) && (cluster2 <= lastFileDataCluster)) { //else if ((cluster>lastDirEntCluster)&&(cluster<=lastFileDataCluster)) { + fileLBA = currLBA - (filesysData-32)*512; // 32 = # sectors used for the root entries + + // Check if the read is from the currently opened file + if ((fileLBA >= fileStartLBA) && (fileLBA < fileEndLBA)) { + cluster = (fileLBA / (512 * SECPERCLUS)); + s = fread_buffered(activeDirEnt,cluster-dirEntries[activeDirEnt].startCluster,(fileLBA-fileStartLBA)&(BYTESPERCLUS-1)); + } else { + for (i=0; i=(dirEntries[i].startCluster*512*SECPERCLUS)) && + (fileLBA <(dirEntries[i].startCluster*512*SECPERCLUS)+dirEntries[i].fileSize) && + ((dirEntries[i].attrib & (ATTRIB_DIR|ATTRIB_LFN))==0)) { + cluster = (fileLBA / (512 * SECPERCLUS)); + s = fread_buffered(i,cluster-dirEntries[i].startCluster,fileLBA&(BYTESPERCLUS-1)); + break; + } + } + } + } + currLBA += 2; + return s; + } + + } else if (address == CF_REG_CMD) { + s = 0; + return 0; + + } else if (address == CF_REG_LBA1) { + s = cf_reg_lba1; + return s; + } +} + + + + +/* Write to one of the CF device registers */ +void cflash_write(unsigned int address,unsigned int data) { + u32 cluster,cluster2,cluster3,fileLBA; + int i,j,k,l; + unsigned char *p; + u16 s; + DIR_ENT *d; + + if (address==CF_REG_STS) { + cf_reg_sts = data&0xFFFF; + + } else if (address==CF_REG_DATA) { + + } else if (address==CF_REG_CMD) { + cf_reg_cmd = data&0xFF; + cf_reg_sts = 0x58; // READY + + } else if (address==CF_REG_LBA1) { + cf_reg_lba1 = data&0xFF; + currLBA = (currLBA&0xFFFFFF00)|cf_reg_lba1; + + } else if (address==CF_REG_LBA2) { + cf_reg_lba2 = data&0xFF; + currLBA = (currLBA&0xFFFF00FF)|(cf_reg_lba2<<8); + + } else if (address==CF_REG_LBA3) { + cf_reg_lba3 = data&0xFF; + currLBA = (currLBA&0xFF00FFFF)|(cf_reg_lba3<<16); + + } else if (address==CF_REG_LBA4) { + cf_reg_lba4 = data&0xFF; + currLBA = (currLBA&0x00FFFFFF)|((cf_reg_lba4&0x0F)<<24); + currLBA *= 512; + } +} + + + +void cflash_close() { + int i; + + if (cflashDeviceEnabled) { + cflashDeviceEnabled = FALSE; + + for (i=0; i