From: chaoskagami Date: Mon, 23 May 2016 23:56:49 +0000 (-0400) Subject: Reformat all the source code X-Git-Tag: stable-1~48 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=a9bfb3fa6d989e8c33d0c2483032a2f125b11996;p=corbenik%2Fcorbenik.git Reformat all the source code --- diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..136d427 --- /dev/null +++ b/.clang-format @@ -0,0 +1,67 @@ +--- +Language: Cpp +# BasedOnStyle: Mozilla +AccessModifierOffset: -2 +AlignAfterOpenBracket: true +AlignConsecutiveAssignments: false +AlignEscapedNewlinesLeft: false +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: TopLevel +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Mozilla +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + diff --git a/Makefile b/Makefile index ecb94ee..66e556c 100644 --- a/Makefile +++ b/Makefile @@ -41,6 +41,10 @@ external: .PHONY: a9lh a9lh: $(dir_out)/arm9loaderhax.bin +.PHONY: reformat +reformat: + clang-format -i $(dir_source)/*.{c,h} $(dir_source)/*/*.{c,h} external/loader/source/*.{c,h} external/loader/source/*/*.{c,h} + host/langemu.conf: echo "Generating langemu.conf - may take a bit" cd host && ./generate_langemu_conf.sh diff --git a/external/loader/source/config.h b/external/loader/source/config.h index 9e298f3..a9bb6ae 100644 --- a/external/loader/source/config.h +++ b/external/loader/source/config.h @@ -6,18 +6,21 @@ __attribute__((unused)) static unsigned int config_version = 1; #define CONFIG_MAGIC "OVAN" // Structure of config file -struct config_file { - char magic[4]; // "OVAN" for shits and giggles again. +struct config_file +{ + char magic[4]; // "OVAN" for shits and giggles again. - uint32_t config_ver; // Config file version. + uint32_t config_ver; // Config file version. - uint8_t options[256]; // Options in the menu - deliberately large to avoid config version bumps. + uint8_t options[256]; // Options in the menu - deliberately large to avoid + // config version bumps. - uint64_t patch_ids[256]; // What patches are enabled by UUID. 256 is an arbitrary limit - contact me if you hit it. -}__attribute__((packed)); + uint64_t patch_ids[256]; // What patches are enabled by UUID. 256 is an + // arbitrary limit - contact me if you hit it. +} __attribute__((packed)); -#define OPTION_LOADER_CPU_L2 11 // Enable L2 cache. +#define OPTION_LOADER_CPU_L2 11 // Enable L2 cache. #define OPTION_LOADER_CPU_800MHZ 12 // Enable 800Mhz mode. -#define OPTION_LOADER_LANGEMU 13 // Enable 800Mhz mode. +#define OPTION_LOADER_LANGEMU 13 // Enable 800Mhz mode. #endif diff --git a/external/loader/source/exheader.h b/external/loader/source/exheader.h index dccb083..394f351 100644 --- a/external/loader/source/exheader.h +++ b/external/loader/source/exheader.h @@ -4,90 +4,91 @@ typedef struct { - u8 reserved[5]; - u8 flag; - u8 remasterversion[2]; + u8 reserved[5]; + u8 flag; + u8 remasterversion[2]; } PACKED exheader_systeminfoflags; typedef struct { - u32 address; - u32 nummaxpages; - u32 codesize; + u32 address; + u32 nummaxpages; + u32 codesize; } PACKED exheader_codesegmentinfo; typedef struct { - u8 name[8]; - exheader_systeminfoflags flags; - exheader_codesegmentinfo text; - u8 stacksize[4]; - exheader_codesegmentinfo ro; - u8 reserved[4]; - exheader_codesegmentinfo data; - u32 bsssize; + u8 name[8]; + exheader_systeminfoflags flags; + exheader_codesegmentinfo text; + u8 stacksize[4]; + exheader_codesegmentinfo ro; + u8 reserved[4]; + exheader_codesegmentinfo data; + u32 bsssize; } PACKED exheader_codesetinfo; typedef struct { - u64 programid[0x30]; + u64 programid[0x30]; } PACKED exheader_dependencylist; typedef struct { - u8 savedatasize[4]; - u8 reserved[4]; - u8 jumpid[8]; - u8 reserved2[0x30]; + u8 savedatasize[4]; + u8 reserved[4]; + u8 jumpid[8]; + u8 reserved2[0x30]; } PACKED exheader_systeminfo; typedef struct { - u8 extsavedataid[8]; - u8 systemsavedataid[8]; - u8 reserved[8]; - u8 accessinfo[7]; - u8 otherattributes; + u8 extsavedataid[8]; + u8 systemsavedataid[8]; + u8 reserved[8]; + u8 accessinfo[7]; + u8 otherattributes; } PACKED exheader_storageinfo; // New3DS speed is flags[1]:1 typedef struct { - u64 programid; - u8 flags[8]; - u16 resourcelimitdescriptor[0x10]; - exheader_storageinfo storageinfo; - u64 serviceaccesscontrol[0x20]; - u8 reserved[0x1f]; - u8 resourcelimitcategory; + u64 programid; + u8 flags[8]; + u16 resourcelimitdescriptor[0x10]; + exheader_storageinfo storageinfo; + u64 serviceaccesscontrol[0x20]; + u8 reserved[0x1f]; + u8 resourcelimitcategory; } PACKED exheader_arm11systemlocalcaps; typedef struct { - u32 descriptors[28]; - u8 reserved[0x10]; + u32 descriptors[28]; + u8 reserved[0x10]; } PACKED exheader_arm11kernelcapabilities; typedef struct { - u8 descriptors[15]; - u8 descversion; + u8 descriptors[15]; + u8 descversion; } PACKED exheader_arm9accesscontrol; typedef struct { - exheader_codesetinfo codesetinfo; - exheader_dependencylist deplist; - exheader_systeminfo systeminfo; - exheader_arm11systemlocalcaps arm11systemlocalcaps; - exheader_arm11kernelcapabilities arm11kernelcaps; - exheader_arm9accesscontrol arm9accesscontrol; - struct { - u8 signature[0x100]; - u8 ncchpubkeymodulus[0x100]; - exheader_arm11systemlocalcaps arm11systemlocalcaps; - exheader_arm11kernelcapabilities arm11kernelcaps; - exheader_arm9accesscontrol arm9accesscontrol; - } PACKED accessdesc; + exheader_codesetinfo codesetinfo; + exheader_dependencylist deplist; + exheader_systeminfo systeminfo; + exheader_arm11systemlocalcaps arm11systemlocalcaps; + exheader_arm11kernelcapabilities arm11kernelcaps; + exheader_arm9accesscontrol arm9accesscontrol; + struct + { + u8 signature[0x100]; + u8 ncchpubkeymodulus[0x100]; + exheader_arm11systemlocalcaps arm11systemlocalcaps; + exheader_arm11kernelcapabilities arm11kernelcaps; + exheader_arm9accesscontrol arm9accesscontrol; + } PACKED accessdesc; } PACKED exheader_header; diff --git a/external/loader/source/fsldr.c b/external/loader/source/fsldr.c index fbc97be..eccc757 100644 --- a/external/loader/source/fsldr.c +++ b/external/loader/source/fsldr.c @@ -9,101 +9,111 @@ static Handle fsldrHandle; static int fsldrRefCount; // MAKE SURE fsreg has been init before calling this -static Result fsldrPatchPermissions(void) +static Result +fsldrPatchPermissions(void) { - u32 pid; - Result res; - FS_ProgramInfo info; - u32 storage[8] = {0}; - - storage[6] = 0x680; // SDMC access and NAND access flag - info.programId = 0x0004013000001302LL; // loader PID - info.mediaType = MEDIATYPE_NAND; - res = svcGetProcessId(&pid, 0xFFFF8001); - if (R_SUCCEEDED(res)) - { - res = FSREG_Register(pid, 0xFFFF000000000000LL, &info, (u8 *)storage); - } - return res; + u32 pid; + Result res; + FS_ProgramInfo info; + u32 storage[8] = { 0 }; + + storage[6] = 0x680; // SDMC access and NAND access flag + info.programId = 0x0004013000001302LL; // loader PID + info.mediaType = MEDIATYPE_NAND; + res = svcGetProcessId(&pid, 0xFFFF8001); + if (R_SUCCEEDED(res)) { + res = FSREG_Register(pid, 0xFFFF000000000000LL, &info, (u8*)storage); + } + return res; } -Result fsldrInit(void) +Result +fsldrInit(void) { - Result ret = 0; - - if (AtomicPostIncrement(&fsldrRefCount)) return 0; - - ret = srvSysGetServiceHandle(&fsldrHandle, "fs:LDR"); - if (R_SUCCEEDED(ret)) - { - fsldrPatchPermissions(); - ret = FSLDR_InitializeWithSdkVersion(fsldrHandle, SDK_VERSION); - ret = FSLDR_SetPriority(0); - if (R_FAILED(ret)) svcBreak(USERBREAK_ASSERT); - } - else - { - AtomicDecrement(&fsldrRefCount); - } - - return ret; + Result ret = 0; + + if (AtomicPostIncrement(&fsldrRefCount)) + return 0; + + ret = srvSysGetServiceHandle(&fsldrHandle, "fs:LDR"); + if (R_SUCCEEDED(ret)) { + fsldrPatchPermissions(); + ret = FSLDR_InitializeWithSdkVersion(fsldrHandle, SDK_VERSION); + ret = FSLDR_SetPriority(0); + if (R_FAILED(ret)) + svcBreak(USERBREAK_ASSERT); + } else { + AtomicDecrement(&fsldrRefCount); + } + + return ret; } -void fsldrExit(void) +void +fsldrExit(void) { - if (AtomicDecrement(&fsldrRefCount)) return; - svcCloseHandle(fsldrHandle); + if (AtomicDecrement(&fsldrRefCount)) + return; + svcCloseHandle(fsldrHandle); } -Result FSLDR_InitializeWithSdkVersion(Handle session, u32 version) +Result +FSLDR_InitializeWithSdkVersion(Handle session, u32 version) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x861,1,2); // 0x8610042 - cmdbuf[1] = version; - cmdbuf[2] = 32; + cmdbuf[0] = IPC_MakeHeader(0x861, 1, 2); // 0x8610042 + cmdbuf[1] = version; + cmdbuf[2] = 32; - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(session))) return ret; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(session))) + return ret; - return cmdbuf[1]; + return cmdbuf[1]; } -Result FSLDR_SetPriority(u32 priority) +Result +FSLDR_SetPriority(u32 priority) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x862,1,0); // 0x8620040 - cmdbuf[1] = priority; + cmdbuf[0] = IPC_MakeHeader(0x862, 1, 0); // 0x8620040 + cmdbuf[1] = priority; - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) + return ret; - return cmdbuf[1]; + return cmdbuf[1]; } -Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes) +Result +FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, + FS_Path filePath, u32 openFlags, u32 attributes) { - u32 *cmdbuf = getThreadCommandBuffer(); - - cmdbuf[0] = IPC_MakeHeader(0x803,8,4); // 0x8030204 - cmdbuf[1] = 0; - cmdbuf[2] = archiveId; - cmdbuf[3] = archivePath.type; - cmdbuf[4] = archivePath.size; - cmdbuf[5] = filePath.type; - cmdbuf[6] = filePath.size; - cmdbuf[7] = openFlags; - cmdbuf[8] = attributes; - cmdbuf[9] = IPC_Desc_StaticBuffer(archivePath.size, 2); - cmdbuf[10] = (u32)archivePath.data; - cmdbuf[11] = IPC_Desc_StaticBuffer(filePath.size, 0); - cmdbuf[12] = (u32)filePath.data; - - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) return ret; - - if(out) *out = cmdbuf[3]; - - return cmdbuf[1]; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x803, 8, 4); // 0x8030204 + cmdbuf[1] = 0; + cmdbuf[2] = archiveId; + cmdbuf[3] = archivePath.type; + cmdbuf[4] = archivePath.size; + cmdbuf[5] = filePath.type; + cmdbuf[6] = filePath.size; + cmdbuf[7] = openFlags; + cmdbuf[8] = attributes; + cmdbuf[9] = IPC_Desc_StaticBuffer(archivePath.size, 2); + cmdbuf[10] = (u32)archivePath.data; + cmdbuf[11] = IPC_Desc_StaticBuffer(filePath.size, 0); + cmdbuf[12] = (u32)filePath.data; + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsldrHandle))) + return ret; + + if (out) + *out = cmdbuf[3]; + + return cmdbuf[1]; } diff --git a/external/loader/source/fsldr.h b/external/loader/source/fsldr.h index 1e483e5..8dfcdd1 100644 --- a/external/loader/source/fsldr.h +++ b/external/loader/source/fsldr.h @@ -6,4 +6,6 @@ Result fsldrInit(void); void fsldrExit(void); Result FSLDR_InitializeWithSdkVersion(Handle session, u32 version); Result FSLDR_SetPriority(u32 priority); -Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 openFlags, u32 attributes); \ No newline at end of file +Result FSLDR_OpenFileDirectly(Handle* out, FS_ArchiveID archiveId, + FS_Path archivePath, FS_Path filePath, + u32 openFlags, u32 attributes); \ No newline at end of file diff --git a/external/loader/source/fsreg.c b/external/loader/source/fsreg.c index d8301bb..2c638b0 100644 --- a/external/loader/source/fsreg.c +++ b/external/loader/source/fsreg.c @@ -6,111 +6,130 @@ static Handle fsregHandle; static int fsregRefCount; -Result fsregInit(void) +Result +fsregInit(void) { - Result ret = 0; + Result ret = 0; - if (AtomicPostIncrement(&fsregRefCount)) return 0; + if (AtomicPostIncrement(&fsregRefCount)) + return 0; - ret = srvSysGetServiceHandle(&fsregHandle, "fs:REG"); + ret = srvSysGetServiceHandle(&fsregHandle, "fs:REG"); - if (R_FAILED(ret)) AtomicDecrement(&fsregRefCount); - return ret; + if (R_FAILED(ret)) + AtomicDecrement(&fsregRefCount); + return ret; } -void fsregExit(void) +void +fsregExit(void) { - if (AtomicDecrement(&fsregRefCount)) return; - svcCloseHandle(fsregHandle); + if (AtomicDecrement(&fsregRefCount)) + return; + svcCloseHandle(fsregHandle); } -Result FSREG_CheckHostLoadId(u64 prog_handle) +Result +FSREG_CheckHostLoadId(u64 prog_handle) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x406,2,0); // 0x4060080 - cmdbuf[1] = (u32) (prog_handle); - cmdbuf[2] = (u32) (prog_handle >> 32); + cmdbuf[0] = IPC_MakeHeader(0x406, 2, 0); // 0x4060080 + cmdbuf[1] = (u32)(prog_handle); + cmdbuf[2] = (u32)(prog_handle >> 32); - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; - return cmdbuf[1]; + return cmdbuf[1]; } -Result FSREG_LoadProgram(u64 *prog_handle, FS_ProgramInfo *title) +Result +FSREG_LoadProgram(u64* prog_handle, FS_ProgramInfo* title) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x404,4,0); // 0x4040100 - memcpy(&cmdbuf[1], &title->programId, sizeof(u64)); - *(u8 *)&cmdbuf[3] = title->mediaType; - memcpy(((u8 *)&cmdbuf[3])+1, &title->padding, 7); + cmdbuf[0] = IPC_MakeHeader(0x404, 4, 0); // 0x4040100 + memcpy(&cmdbuf[1], &title->programId, sizeof(u64)); + *(u8*)&cmdbuf[3] = title->mediaType; + memcpy(((u8*)&cmdbuf[3]) + 1, &title->padding, 7); - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret; - *prog_handle = *(u64 *)&cmdbuf[2]; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + *prog_handle = *(u64*)&cmdbuf[2]; - return cmdbuf[1]; + return cmdbuf[1]; } -Result FSREG_GetProgramInfo(exheader_header *exheader, u32 entry_count, u64 prog_handle) +Result +FSREG_GetProgramInfo(exheader_header* exheader, u32 entry_count, + u64 prog_handle) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x403,3,0); // 0x40300C0 - cmdbuf[1] = entry_count; - *(u64 *)&cmdbuf[2] = prog_handle; - cmdbuf[64] = ((entry_count << 10) << 14) | 2; - cmdbuf[65] = (u32) exheader; + cmdbuf[0] = IPC_MakeHeader(0x403, 3, 0); // 0x40300C0 + cmdbuf[1] = entry_count; + *(u64*)&cmdbuf[2] = prog_handle; + cmdbuf[64] = ((entry_count << 10) << 14) | 2; + cmdbuf[65] = (u32)exheader; - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; - return cmdbuf[1]; + return cmdbuf[1]; } -Result FSREG_UnloadProgram(u64 prog_handle) +Result +FSREG_UnloadProgram(u64 prog_handle) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x405,2,0); // 0x4050080 - cmdbuf[1] = (u32) (prog_handle); - cmdbuf[2] = (u32) (prog_handle >> 32); + cmdbuf[0] = IPC_MakeHeader(0x405, 2, 0); // 0x4050080 + cmdbuf[1] = (u32)(prog_handle); + cmdbuf[2] = (u32)(prog_handle >> 32); - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; - return cmdbuf[1]; + return cmdbuf[1]; } -Result FSREG_Unregister(u32 pid) +Result +FSREG_Unregister(u32 pid) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x402,1,0); // 0x4020040 - cmdbuf[1] = pid; + cmdbuf[0] = IPC_MakeHeader(0x402, 1, 0); // 0x4020040 + cmdbuf[1] = pid; - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; - return cmdbuf[1]; + return cmdbuf[1]; } -Result FSREG_Register(u32 pid, u64 prog_handle, FS_ProgramInfo *info, void *storageinfo) +Result +FSREG_Register(u32 pid, u64 prog_handle, FS_ProgramInfo* info, + void* storageinfo) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x401,0xf,0); // 0x40103C0 - cmdbuf[1] = pid; - *(u64 *)&cmdbuf[2] = prog_handle; - memcpy(&cmdbuf[4], &info->programId, sizeof(u64)); - *(u8 *)&cmdbuf[6] = info->mediaType; - memcpy(((u8 *)&cmdbuf[6])+1, &info->padding, 7); - memcpy((u8 *)&cmdbuf[8], storageinfo, 32); + cmdbuf[0] = IPC_MakeHeader(0x401, 0xf, 0); // 0x40103C0 + cmdbuf[1] = pid; + *(u64*)&cmdbuf[2] = prog_handle; + memcpy(&cmdbuf[4], &info->programId, sizeof(u64)); + *(u8*)&cmdbuf[6] = info->mediaType; + memcpy(((u8*)&cmdbuf[6]) + 1, &info->padding, 7); + memcpy((u8*)&cmdbuf[8], storageinfo, 32); - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) return ret; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; - return cmdbuf[1]; + return cmdbuf[1]; } diff --git a/external/loader/source/fsreg.h b/external/loader/source/fsreg.h index c2de1ed..c7f56bb 100644 --- a/external/loader/source/fsreg.h +++ b/external/loader/source/fsreg.h @@ -6,8 +6,10 @@ Result fsregInit(void); void fsregExit(void); Result FSREG_CheckHostLoadId(u64 prog_handle); -Result FSREG_LoadProgram(u64 *prog_handle, FS_ProgramInfo *title); -Result FSREG_GetProgramInfo(exheader_header *exheader, u32 entry_count, u64 prog_handle); +Result FSREG_LoadProgram(u64* prog_handle, FS_ProgramInfo* title); +Result FSREG_GetProgramInfo(exheader_header* exheader, u32 entry_count, + u64 prog_handle); Result FSREG_UnloadProgram(u64 prog_handle); Result FSREG_Unregister(u32 pid); -Result FSREG_Register(u32 pid, u64 prog_handle, FS_ProgramInfo *info, void *storageinfo); +Result FSREG_Register(u32 pid, u64 prog_handle, FS_ProgramInfo* info, + void* storageinfo); diff --git a/external/loader/source/ifile.c b/external/loader/source/ifile.c index 3babbab..746b02a 100644 --- a/external/loader/source/ifile.c +++ b/external/loader/source/ifile.c @@ -5,69 +5,73 @@ // TODO - What exactly is the point of these? Can't we just use FSFILE directly? // These are just shitty wrappers. -Result IFile_Open(IFile *file, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 flags) +Result +IFile_Open(IFile* file, FS_ArchiveID archiveId, FS_Path archivePath, + FS_Path filePath, u32 flags) { - Result res; + Result res; - res = FSLDR_OpenFileDirectly(&file->handle, archiveId, archivePath, filePath, flags, 0); - file->pos = 0; - file->size = 0; - return res; + res = FSLDR_OpenFileDirectly(&file->handle, archiveId, archivePath, + filePath, flags, 0); + file->pos = 0; + file->size = 0; + return res; } -Result IFile_Close(IFile *file) +Result +IFile_Close(IFile* file) { - return FSFILE_Close(file->handle); + return FSFILE_Close(file->handle); } -Result IFile_GetSize(IFile *file, u64 *size) +Result +IFile_GetSize(IFile* file, u64* size) { - Result res; + Result res; - res = FSFILE_GetSize(file->handle, size); - file->size = *size; - return res; + res = FSFILE_GetSize(file->handle, size); + file->size = *size; + return res; } -Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len) +Result +IFile_Read(IFile* file, u64* total, void* buffer, u32 len) { - u32 read; - u32 left; - char *buf; - u64 cur; - Result res; + u32 read; + u32 left; + char* buf; + u64 cur; + Result res; - if (len == 0) - { - *total = 0; - return 0; - } - - buf = (char *)buffer; - cur = 0; - left = len; - while (1) - { - res = FSFILE_Read(file->handle, &read, file->pos, buf, left); - if (R_FAILED(res)) - { - break; + if (len == 0) { + *total = 0; + return 0; } - cur += read; - file->pos += read; - if (read == left) - { - break; + buf = (char*)buffer; + cur = 0; + left = len; + while (1) { + res = FSFILE_Read(file->handle, &read, file->pos, buf, left); + if (R_FAILED(res)) { + break; + } + + cur += read; + file->pos += read; + if (read == left) { + break; + } + buf += read; + left -= read; } - buf += read; - left -= read; - } - *total = cur; - return res; + *total = cur; + return res; } -Result IFile_Write(IFile *file, u64 *total, void *buffer, u32 len) { - return 1; // FIXME - Not yet implemented. +Result +IFile_Write(IFile* file, u64* total, void* buffer, u32 len) +{ + return 1; // FIXME - Not yet implemented. } diff --git a/external/loader/source/ifile.h b/external/loader/source/ifile.h index a4134d9..8c15e21 100644 --- a/external/loader/source/ifile.h +++ b/external/loader/source/ifile.h @@ -4,13 +4,14 @@ typedef struct { - Handle handle; - u64 pos; - u64 size; + Handle handle; + u64 pos; + u64 size; } IFile; -Result IFile_Open(IFile *file, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 flags); -Result IFile_Close(IFile *file); -Result IFile_GetSize(IFile *file, u64 *size); -Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len); -Result IFile_Write(IFile *file, u64 *total, void *buffer, u32 len); +Result IFile_Open(IFile* file, FS_ArchiveID archiveId, FS_Path archivePath, + FS_Path filePath, u32 flags); +Result IFile_Close(IFile* file); +Result IFile_GetSize(IFile* file, u64* size); +Result IFile_Read(IFile* file, u64* total, void* buffer, u32 len); +Result IFile_Write(IFile* file, u64* total, void* buffer, u32 len); diff --git a/external/loader/source/internal.h b/external/loader/source/internal.h index 1d70036..3ea12da 100644 --- a/external/loader/source/internal.h +++ b/external/loader/source/internal.h @@ -1,4 +1,5 @@ #pragma once -// This is a GCC builtin, and so there's no need to carry an implementation here. +// This is a GCC builtin, and so there's no need to carry an implementation +// here. void* memcpy(void* dest, const void* src, size_t len); diff --git a/external/loader/source/loader.c b/external/loader/source/loader.c index 3bb93b6..4db617f 100644 --- a/external/loader/source/loader.c +++ b/external/loader/source/loader.c @@ -9,429 +9,439 @@ #include "lzss.h" #include "internal.h" -// TODO - a lot of this is unecessarily verbose and shitty. Clean it up to be tidy. +// TODO - a lot of this is unecessarily verbose and shitty. Clean it up to be +// tidy. #define MAX_SESSIONS 1 -const char CODE_PATH[] = {0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00}; +const char CODE_PATH[] = { 0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, + 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00 }; typedef struct { - u32 text_addr; - u32 text_size; - u32 ro_addr; - u32 ro_size; - u32 data_addr; - u32 data_size; - u32 total_size; + u32 text_addr; + u32 text_size; + u32 ro_addr; + u32 ro_size; + u32 data_addr; + u32 data_size; + u32 total_size; } prog_addrs_t; -static Handle g_handles[MAX_SESSIONS+2]; +static Handle g_handles[MAX_SESSIONS + 2]; static int g_active_handles; static u64 g_cached_prog_handle; static exheader_header g_exheader; static char g_ret_buf[1024]; -static Result allocate_shared_mem(prog_addrs_t *shared, prog_addrs_t *vaddr, int flags) +static Result +allocate_shared_mem(prog_addrs_t* shared, prog_addrs_t* vaddr, int flags) { - // Somehow, we need to allow reallocating. - - u32 dummy; - - memcpy(shared, vaddr, sizeof(prog_addrs_t)); - shared->text_addr = 0x10000000; // Code is forcibly relocated to this address to kill ASLR (I believe.) - shared->ro_addr = shared->text_addr + (shared->text_size << 12); - shared->data_addr = shared->ro_addr + (shared->ro_size << 12); - return svcControlMemory(&dummy, shared->text_addr, 0, shared->total_size << 12, (flags & 0xF00) | MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); + // Somehow, we need to allow reallocating. + + u32 dummy; + + memcpy(shared, vaddr, sizeof(prog_addrs_t)); + shared->text_addr = 0x10000000; // Code is forcibly relocated to this + // address to kill ASLR (I believe.) + shared->ro_addr = shared->text_addr + (shared->text_size << 12); + shared->data_addr = shared->ro_addr + (shared->ro_size << 12); + return svcControlMemory( + &dummy, shared->text_addr, 0, shared->total_size << 12, + (flags & 0xF00) | MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); } -static Result load_code(u64 progid, prog_addrs_t *shared, prog_addrs_t *original, u64 prog_handle, int is_compressed) +static Result +load_code(u64 progid, prog_addrs_t* shared, prog_addrs_t* original, + u64 prog_handle, int is_compressed) { - IFile file; - FS_Path archivePath; - FS_Path path; - Result res; - u64 size; - u64 total; - - archivePath.type = PATH_BINARY; - archivePath.data = &prog_handle; - archivePath.size = 8; - - path.type = PATH_BINARY; - path.data = CODE_PATH; - path.size = sizeof(CODE_PATH); - - if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, path, FS_OPEN_READ))) - { - svcBreak(USERBREAK_ASSERT); - } - - // get file size - if (R_FAILED(IFile_GetSize(&file, &size))) - { - IFile_Close(&file); - svcBreak(USERBREAK_ASSERT); - } - - // check size - if (size > (u64)shared->total_size << 12) - { - IFile_Close(&file); - return 0xC900464F; - } - - // read code - res = IFile_Read(&file, &total, (void *)shared->text_addr, size); - IFile_Close(&file); // done reading - if (R_FAILED(res)) - { - svcBreak(USERBREAK_ASSERT); - } - - // decompress in place - if (is_compressed) - { - lzss_decompress((u8 *)shared->text_addr + size); - } - - // Patch segments - patch_text(progid, (u8 *)shared->text_addr, shared->text_size << 12, original->text_size << 12); - patch_data(progid, (u8 *)shared->data_addr, shared->data_size << 12, original->data_size << 12); - patch_ro (progid, (u8 *)shared->ro_addr, shared->ro_size << 12, original->ro_size << 12); - - return 0; + IFile file; + FS_Path archivePath; + FS_Path path; + Result res; + u64 size; + u64 total; + + archivePath.type = PATH_BINARY; + archivePath.data = &prog_handle; + archivePath.size = 8; + + path.type = PATH_BINARY; + path.data = CODE_PATH; + path.size = sizeof(CODE_PATH); + + if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, + path, FS_OPEN_READ))) { + svcBreak(USERBREAK_ASSERT); + } + + // get file size + if (R_FAILED(IFile_GetSize(&file, &size))) { + IFile_Close(&file); + svcBreak(USERBREAK_ASSERT); + } + + // check size + if (size > (u64)shared->total_size << 12) { + IFile_Close(&file); + return 0xC900464F; + } + + // read code + res = IFile_Read(&file, &total, (void*)shared->text_addr, size); + IFile_Close(&file); // done reading + if (R_FAILED(res)) { + svcBreak(USERBREAK_ASSERT); + } + + // decompress in place + if (is_compressed) { + lzss_decompress((u8*)shared->text_addr + size); + } + + // Patch segments + patch_text(progid, (u8*)shared->text_addr, shared->text_size << 12, + original->text_size << 12); + patch_data(progid, (u8*)shared->data_addr, shared->data_size << 12, + original->data_size << 12); + patch_ro(progid, (u8*)shared->ro_addr, shared->ro_size << 12, + original->ro_size << 12); + + return 0; } -static Result loader_GetProgramInfo(exheader_header *exheader, u64 prog_handle) +static Result +loader_GetProgramInfo(exheader_header* exheader, u64 prog_handle) { - Result res; - - if (prog_handle >> 32 == 0xFFFF0000) - { - return FSREG_GetProgramInfo(exheader, 1, prog_handle); - } - else - { - res = FSREG_CheckHostLoadId(prog_handle); - //if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32)) - //so use PXIPM if FSREG fails OR returns "info", is the second condition a bug? - if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) - { - return PXIPM_GetProgramInfo(exheader, prog_handle); - } - else - { - return FSREG_GetProgramInfo(exheader, 1, prog_handle); + Result res; + + if (prog_handle >> 32 == 0xFFFF0000) { + return FSREG_GetProgramInfo(exheader, 1, prog_handle); + } else { + res = FSREG_CheckHostLoadId(prog_handle); + // if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res + // >> 27)-32)) + // so use PXIPM if FSREG fails OR returns "info", is the second + // condition a bug? + if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) { + return PXIPM_GetProgramInfo(exheader, prog_handle); + } else { + return FSREG_GetProgramInfo(exheader, 1, prog_handle); + } } - } } -extern void KernelSetState(unsigned int, unsigned int, unsigned int, unsigned int); +extern void KernelSetState(unsigned int, unsigned int, unsigned int, + unsigned int); -static void ConfigureNew3DSCPU(u8 mode) { - // 10 -> r0 (Type) - // mode -> r1 (Mode) - // svc 0x7C +static void +ConfigureNew3DSCPU(u8 mode) +{ + // 10 -> r0 (Type) + // mode -> r1 (Mode) + // svc 0x7C - KernelSetState(10, mode, 0, 0); // Yes, we syscall directly. Problem? + KernelSetState(10, mode, 0, 0); // Yes, we syscall directly. Problem? } -static Result loader_LoadProcess(Handle *process, u64 prog_handle) +static Result +loader_LoadProcess(Handle* process, u64 prog_handle) { - Result res; - int count; - u32 flags; - u32 desc; - u32 dummy; - prog_addrs_t shared_addr; - prog_addrs_t vaddr; - prog_addrs_t original_vaddr; - Handle codeset; - CodeSetInfo codesetinfo; - u32 data_mem_size; - u64 progid; - u32 text_grow, data_grow, ro_grow; - - // make sure the cached info corrosponds to the current prog_handle - if (g_cached_prog_handle != prog_handle) - { - res = loader_GetProgramInfo(&g_exheader, prog_handle); - g_cached_prog_handle = prog_handle; - if (res < 0) - { - g_cached_prog_handle = 0; - return res; + Result res; + int count; + u32 flags; + u32 desc; + u32 dummy; + prog_addrs_t shared_addr; + prog_addrs_t vaddr; + prog_addrs_t original_vaddr; + Handle codeset; + CodeSetInfo codesetinfo; + u32 data_mem_size; + u64 progid; + u32 text_grow, data_grow, ro_grow; + + // make sure the cached info corrosponds to the current prog_handle + if (g_cached_prog_handle != prog_handle) { + res = loader_GetProgramInfo(&g_exheader, prog_handle); + g_cached_prog_handle = prog_handle; + if (res < 0) { + g_cached_prog_handle = 0; + return res; + } } - } - - // get kernel flags - flags = 0; - for (count = 0; count < 28; count++) - { - desc = g_exheader.arm11kernelcaps.descriptors[count]; - if (0x1FE == desc >> 23) - { - flags = desc & 0xF00; + + // get kernel flags + flags = 0; + for (count = 0; count < 28; count++) { + desc = g_exheader.arm11kernelcaps.descriptors[count]; + if (0x1FE == desc >> 23) { + flags = desc & 0xF00; + } } - } - if (flags == 0) - { - return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, 1, 2); - } - - load_config(); // First order of business - we need the config file. - - // Check and set the CPU mode. Possible values: 0 - Keep o3ds speed, 1 - n3ds speed, -1 force o3ds - // This is A-OK because the CPU speed parameter isn't passed through to any kernel function; meaning it has already been set. - u8 n3ds_mode = g_exheader.arm11systemlocalcaps.flags[1] & 0x3; - u8 cpu_mode = get_cpumode(progid); - if (cpu_mode != 0xFF) { // Skip? - u8 mode = n3ds_mode | cpu_mode; // Keep flags set by exheader. - ConfigureNew3DSCPU(mode); // We do not use PXIPM because we are a sysmodule. It doesn't make sense. - } - - // What the addressing info would be if not for expansion. This is passed to patchCode. - original_vaddr.text_size = (g_exheader.codesetinfo.text.codesize + 4095) >> 12; // (Text size + one page) >> page size - original_vaddr.ro_size = (g_exheader.codesetinfo.ro.codesize + 4095) >> 12; - original_vaddr.data_size = (g_exheader.codesetinfo.data.codesize + 4095) >> 12; - original_vaddr.total_size = original_vaddr.text_size + original_vaddr.ro_size + original_vaddr.data_size; - - // Allow changing code, ro, data sizes to allow adding code - text_grow = get_text_extend(progid, g_exheader.codesetinfo.text.codesize); - ro_grow = get_ro_extend(progid, g_exheader.codesetinfo.ro.codesize); - data_grow = get_data_extend(progid, g_exheader.codesetinfo.data.codesize); - - // One page is 4096 bytes, thus all the 4095 constants. - - // Allocate process memory, growing as needed for extra patches - vaddr.text_addr = g_exheader.codesetinfo.text.address; - vaddr.text_size = (g_exheader.codesetinfo.text.codesize + text_grow + 4095) >> 12; // (Text size + one page) >> page size - vaddr.ro_addr = g_exheader.codesetinfo.ro.address; - vaddr.ro_size = (g_exheader.codesetinfo.ro.codesize + ro_grow + 4095) >> 12; - vaddr.data_addr = g_exheader.codesetinfo.data.address; - vaddr.data_size = (g_exheader.codesetinfo.data.codesize + data_grow + 4095) >> 12; - data_mem_size = (g_exheader.codesetinfo.data.codesize + text_grow + g_exheader.codesetinfo.bsssize + 4095) >> 12; - vaddr.total_size = vaddr.text_size + vaddr.ro_size + vaddr.data_size + text_grow + ro_grow + data_grow; - - if ((res = allocate_shared_mem(&shared_addr, &vaddr, flags)) < 0) - { - return res; - } - - // load code - progid = g_exheader.arm11systemlocalcaps.programid; - if ((res = load_code(progid, &shared_addr, &original_vaddr, prog_handle, g_exheader.codesetinfo.flags.flag & 1)) >= 0) - { - memcpy(&codesetinfo.name, g_exheader.codesetinfo.name, 8); - codesetinfo.program_id = progid; - codesetinfo.text_addr = vaddr.text_addr; - codesetinfo.text_size = vaddr.text_size; - codesetinfo.text_size_total = vaddr.text_size; - codesetinfo.ro_addr = vaddr.ro_addr; - codesetinfo.ro_size = vaddr.ro_size; - codesetinfo.ro_size_total = vaddr.ro_size; - codesetinfo.rw_addr = vaddr.data_addr; - codesetinfo.rw_size = vaddr.data_size; - codesetinfo.rw_size_total = data_mem_size; - res = svcCreateCodeSet(&codeset, &codesetinfo, (void *)shared_addr.text_addr, (void *)shared_addr.ro_addr, (void *)shared_addr.data_addr); - if (res >= 0) - { - res = svcCreateProcess(process, codeset, g_exheader.arm11kernelcaps.descriptors, count); - svcCloseHandle(codeset); - if (res >= 0) - { - return 0; - } + if (flags == 0) { + return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, 1, 2); + } + + load_config(); // First order of business - we need the config file. + + // Check and set the CPU mode. Possible values: 0 - Keep o3ds speed, 1 - + // n3ds speed, -1 force o3ds + // This is A-OK because the CPU speed parameter isn't passed through to any + // kernel function; meaning it has already been set. + u8 n3ds_mode = g_exheader.arm11systemlocalcaps.flags[1] & 0x3; + u8 cpu_mode = get_cpumode(progid); + if (cpu_mode != 0xFF) { // Skip? + u8 mode = n3ds_mode | cpu_mode; // Keep flags set by exheader. + ConfigureNew3DSCPU(mode); // We do not use PXIPM because we are a + // sysmodule. It doesn't make sense. + } + + // What the addressing info would be if not for expansion. This is passed to + // patchCode. + original_vaddr.text_size = (g_exheader.codesetinfo.text.codesize + 4095) >> + 12; // (Text size + one page) >> page size + original_vaddr.ro_size = (g_exheader.codesetinfo.ro.codesize + 4095) >> 12; + original_vaddr.data_size = + (g_exheader.codesetinfo.data.codesize + 4095) >> 12; + original_vaddr.total_size = original_vaddr.text_size + + original_vaddr.ro_size + + original_vaddr.data_size; + + // Allow changing code, ro, data sizes to allow adding code + text_grow = get_text_extend(progid, g_exheader.codesetinfo.text.codesize); + ro_grow = get_ro_extend(progid, g_exheader.codesetinfo.ro.codesize); + data_grow = get_data_extend(progid, g_exheader.codesetinfo.data.codesize); + + // One page is 4096 bytes, thus all the 4095 constants. + + // Allocate process memory, growing as needed for extra patches + vaddr.text_addr = g_exheader.codesetinfo.text.address; + vaddr.text_size = + (g_exheader.codesetinfo.text.codesize + text_grow + 4095) >> + 12; // (Text size + one page) >> page size + vaddr.ro_addr = g_exheader.codesetinfo.ro.address; + vaddr.ro_size = (g_exheader.codesetinfo.ro.codesize + ro_grow + 4095) >> 12; + vaddr.data_addr = g_exheader.codesetinfo.data.address; + vaddr.data_size = + (g_exheader.codesetinfo.data.codesize + data_grow + 4095) >> 12; + data_mem_size = (g_exheader.codesetinfo.data.codesize + text_grow + + g_exheader.codesetinfo.bsssize + 4095) >> + 12; + vaddr.total_size = vaddr.text_size + vaddr.ro_size + vaddr.data_size + + text_grow + ro_grow + data_grow; + + if ((res = allocate_shared_mem(&shared_addr, &vaddr, flags)) < 0) { + return res; + } + + // load code + progid = g_exheader.arm11systemlocalcaps.programid; + if ((res = load_code(progid, &shared_addr, &original_vaddr, prog_handle, + g_exheader.codesetinfo.flags.flag & 1)) >= 0) { + memcpy(&codesetinfo.name, g_exheader.codesetinfo.name, 8); + codesetinfo.program_id = progid; + codesetinfo.text_addr = vaddr.text_addr; + codesetinfo.text_size = vaddr.text_size; + codesetinfo.text_size_total = vaddr.text_size; + codesetinfo.ro_addr = vaddr.ro_addr; + codesetinfo.ro_size = vaddr.ro_size; + codesetinfo.ro_size_total = vaddr.ro_size; + codesetinfo.rw_addr = vaddr.data_addr; + codesetinfo.rw_size = vaddr.data_size; + codesetinfo.rw_size_total = data_mem_size; + res = svcCreateCodeSet( + &codeset, &codesetinfo, (void*)shared_addr.text_addr, + (void*)shared_addr.ro_addr, (void*)shared_addr.data_addr); + if (res >= 0) { + res = + svcCreateProcess(process, codeset, + g_exheader.arm11kernelcaps.descriptors, count); + svcCloseHandle(codeset); + if (res >= 0) { + return 0; + } + } } - } - svcControlMemory(&dummy, shared_addr.text_addr, 0, shared_addr.total_size << 12, MEMOP_FREE, 0); - return res; + svcControlMemory(&dummy, shared_addr.text_addr, 0, + shared_addr.total_size << 12, MEMOP_FREE, 0); + return res; } -static Result loader_RegisterProgram(u64 *prog_handle, FS_ProgramInfo *title, FS_ProgramInfo *update) +static Result +loader_RegisterProgram(u64* prog_handle, FS_ProgramInfo* title, + FS_ProgramInfo* update) { - Result res; - u64 prog_id; - - prog_id = title->programId; - if (prog_id >> 32 != 0xFFFF0000) - { - res = FSREG_CheckHostLoadId(prog_id); - //if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32)) - if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) - { - res = PXIPM_RegisterProgram(prog_handle, title, update); - if (res < 0) - { - return res; - } - if (*prog_handle >> 32 != 0xFFFF0000) - { - res = FSREG_CheckHostLoadId(*prog_handle); - //if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32)) - if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) - { - return 0; + Result res; + u64 prog_id; + + prog_id = title->programId; + if (prog_id >> 32 != 0xFFFF0000) { + res = FSREG_CheckHostLoadId(prog_id); + // if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res + // >> 27)-32)) + if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) { + res = PXIPM_RegisterProgram(prog_handle, title, update); + if (res < 0) { + return res; + } + if (*prog_handle >> 32 != 0xFFFF0000) { + res = FSREG_CheckHostLoadId(*prog_handle); + // if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && + // ((unsigned)res >> 27)-32)) + if (R_FAILED(res) || + (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) { + return 0; + } + } + svcBreak(USERBREAK_ASSERT); } - } - svcBreak(USERBREAK_ASSERT); } - } - - if ((title->mediaType != update->mediaType) || (prog_id != update->programId)) - { - svcBreak(USERBREAK_ASSERT); - } - res = FSREG_LoadProgram(prog_handle, title); - if (R_SUCCEEDED(res)) - { - if (*prog_handle >> 32 == 0xFFFF0000) - { - return 0; + + if ((title->mediaType != update->mediaType) || + (prog_id != update->programId)) { + svcBreak(USERBREAK_ASSERT); } - res = FSREG_CheckHostLoadId(*prog_handle); - //if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32)) - if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) - { - svcBreak(USERBREAK_ASSERT); + res = FSREG_LoadProgram(prog_handle, title); + if (R_SUCCEEDED(res)) { + if (*prog_handle >> 32 == 0xFFFF0000) { + return 0; + } + res = FSREG_CheckHostLoadId(*prog_handle); + // if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res + // >> 27)-32)) + if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) { + svcBreak(USERBREAK_ASSERT); + } } - } - return res; + return res; } -static Result loader_UnregisterProgram(u64 prog_handle) +static Result +loader_UnregisterProgram(u64 prog_handle) { - Result res; - - if (prog_handle >> 32 == 0xFFFF0000) - { - return FSREG_UnloadProgram(prog_handle); - } - else - { - res = FSREG_CheckHostLoadId(prog_handle); - //if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res >> 27)-32)) - if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) - { - return PXIPM_UnregisterProgram(prog_handle); - } - else - { - return FSREG_UnloadProgram(prog_handle); + Result res; + + if (prog_handle >> 32 == 0xFFFF0000) { + return FSREG_UnloadProgram(prog_handle); + } else { + res = FSREG_CheckHostLoadId(prog_handle); + // if ((res >= 0 && (unsigned)res >> 27) || (res < 0 && ((unsigned)res + // >> 27)-32)) + if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) { + return PXIPM_UnregisterProgram(prog_handle); + } else { + return FSREG_UnloadProgram(prog_handle); + } } - } } -static void handle_commands(void) +static void +handle_commands(void) { - FS_ProgramInfo title; - FS_ProgramInfo update; - u32* cmdbuf; - u16 cmdid; - int res; - Handle handle; - u64 prog_handle; - - cmdbuf = getThreadCommandBuffer(); - cmdid = cmdbuf[0] >> 16; - res = 0; - switch (cmdid) - { - case 1: // LoadProcess - { - res = loader_LoadProcess(&handle, *(u64 *)&cmdbuf[1]); - cmdbuf[0] = 0x10042; - cmdbuf[1] = res; - cmdbuf[2] = 16; - cmdbuf[3] = handle; - break; - } - case 2: // RegisterProgram - { - memcpy(&title, &cmdbuf[1], sizeof(FS_ProgramInfo)); - memcpy(&update, &cmdbuf[5], sizeof(FS_ProgramInfo)); - res = loader_RegisterProgram(&prog_handle, &title, &update); - cmdbuf[0] = 0x200C0; - cmdbuf[1] = res; - *(u64 *)&cmdbuf[2] = prog_handle; - break; - } - case 3: // UnregisterProgram - { - if (g_cached_prog_handle == prog_handle) - { - g_cached_prog_handle = 0; - } - cmdbuf[0] = 0x30040; - cmdbuf[1] = loader_UnregisterProgram(*(u64 *)&cmdbuf[1]); - break; - } - case 4: // GetProgramInfo - { - prog_handle = *(u64 *)&cmdbuf[1]; - if (prog_handle != g_cached_prog_handle) - { - res = loader_GetProgramInfo(&g_exheader, prog_handle); - if (res >= 0) + FS_ProgramInfo title; + FS_ProgramInfo update; + u32* cmdbuf; + u16 cmdid; + int res; + Handle handle; + u64 prog_handle; + + cmdbuf = getThreadCommandBuffer(); + cmdid = cmdbuf[0] >> 16; + res = 0; + switch (cmdid) { + case 1: // LoadProcess { - g_cached_prog_handle = prog_handle; + res = loader_LoadProcess(&handle, *(u64*)&cmdbuf[1]); + cmdbuf[0] = 0x10042; + cmdbuf[1] = res; + cmdbuf[2] = 16; + cmdbuf[3] = handle; + break; } - else + case 2: // RegisterProgram { - g_cached_prog_handle = 0; + memcpy(&title, &cmdbuf[1], sizeof(FS_ProgramInfo)); + memcpy(&update, &cmdbuf[5], sizeof(FS_ProgramInfo)); + res = loader_RegisterProgram(&prog_handle, &title, &update); + cmdbuf[0] = 0x200C0; + cmdbuf[1] = res; + *(u64*)&cmdbuf[2] = prog_handle; + break; + } + case 3: // UnregisterProgram + { + if (g_cached_prog_handle == prog_handle) { + g_cached_prog_handle = 0; + } + cmdbuf[0] = 0x30040; + cmdbuf[1] = loader_UnregisterProgram(*(u64*)&cmdbuf[1]); + break; + } + case 4: // GetProgramInfo + { + prog_handle = *(u64*)&cmdbuf[1]; + if (prog_handle != g_cached_prog_handle) { + res = loader_GetProgramInfo(&g_exheader, prog_handle); + if (res >= 0) { + g_cached_prog_handle = prog_handle; + } else { + g_cached_prog_handle = 0; + } + } + memcpy(&g_ret_buf, &g_exheader, 1024); + cmdbuf[0] = 0x40042; + cmdbuf[1] = res; + cmdbuf[2] = 0x1000002; + cmdbuf[3] = (u32)&g_ret_buf; + break; + } + default: // error + { + cmdbuf[0] = 0x40; + cmdbuf[1] = 0xD900182F; + break; } - } - memcpy(&g_ret_buf, &g_exheader, 1024); - cmdbuf[0] = 0x40042; - cmdbuf[1] = res; - cmdbuf[2] = 0x1000002; - cmdbuf[3] = (u32) &g_ret_buf; - break; - } - default: // error - { - cmdbuf[0] = 0x40; - cmdbuf[1] = 0xD900182F; - break; } - } } -static Result should_terminate(int *term_request) +static Result +should_terminate(int* term_request) { - u32 notid; - Result ret; - - ret = srvSysReceiveNotification(¬id); - if (R_FAILED(ret)) - { - return ret; - } - if (notid == 0x100) // term request - { - *term_request = 1; - } - return 0; + u32 notid; + Result ret; + + ret = srvSysReceiveNotification(¬id); + if (R_FAILED(ret)) { + return ret; + } + if (notid == 0x100) // term request + { + *term_request = 1; + } + return 0; } // this is called before main -void __appInit() +void +__appInit() { - srvSysInit(); - fsregInit(); - fsldrInit(); - pxipmInit(); + srvSysInit(); + fsregInit(); + fsldrInit(); + pxipmInit(); } // this is called after main exits -void __appExit() +void +__appExit() { - pxipmExit(); - fsldrExit(); - fsregExit(); - srvSysExit(); + pxipmExit(); + fsldrExit(); + fsregExit(); + srvSysExit(); } // stubs for non-needed pre-main functions @@ -439,132 +449,117 @@ void __sync_init(); void __sync_fini(); void __system_initSyscalls(); -void __ctru_exit() +void +__ctru_exit() { - __appExit(); - __sync_fini(); - svcExitProcess(); + __appExit(); + __sync_fini(); + svcExitProcess(); } -void initSystem() +void +initSystem() { - __sync_init(); - __system_initSyscalls(); - __appInit(); + __sync_init(); + __system_initSyscalls(); + __appInit(); } -int main() +int +main() { - Result ret; - Handle handle; - Handle reply_target; - Handle *srv_handle; - Handle *notification_handle; - s32 index; - int i; - int term_request; - u32* cmdbuf; - - ret = 0; - - srv_handle = &g_handles[1]; - notification_handle = &g_handles[0]; - - if (R_FAILED(srvSysRegisterService(srv_handle, "Loader", MAX_SESSIONS))) - { - svcBreak(USERBREAK_ASSERT); - } - - if (R_FAILED(srvSysEnableNotification(notification_handle))) - { - svcBreak(USERBREAK_ASSERT); - } - - g_active_handles = 2; - g_cached_prog_handle = 0; - index = 1; - - reply_target = 0; - term_request = 0; - do - { - if (reply_target == 0) - { - cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = 0xFFFF0000; + Result ret; + Handle handle; + Handle reply_target; + Handle* srv_handle; + Handle* notification_handle; + s32 index; + int i; + int term_request; + u32* cmdbuf; + + ret = 0; + + srv_handle = &g_handles[1]; + notification_handle = &g_handles[0]; + + if (R_FAILED(srvSysRegisterService(srv_handle, "Loader", MAX_SESSIONS))) { + svcBreak(USERBREAK_ASSERT); } - ret = svcReplyAndReceive(&index, g_handles, g_active_handles, reply_target); - if (R_FAILED(ret)) - { - // check if any handle has been closed - if (ret == (int)0xC920181A) - { - if (index == -1) - { - for (i = 2; i < MAX_SESSIONS+2; i++) - { - if (g_handles[i] == reply_target) - { - index = i; - break; - } - } - } - svcCloseHandle(g_handles[index]); - g_handles[index] = g_handles[g_active_handles-1]; - g_active_handles--; - reply_target = 0; - } - else - { + if (R_FAILED(srvSysEnableNotification(notification_handle))) { svcBreak(USERBREAK_ASSERT); - } } - else - { - // process responses - reply_target = 0; - switch (index) - { - case 0: // notification - { - if (R_FAILED(should_terminate(&term_request))) - { - svcBreak(USERBREAK_ASSERT); - } - break; - } - case 1: // new session - { - if (R_FAILED(svcAcceptSession(&handle, *srv_handle))) - { - svcBreak(USERBREAK_ASSERT); - } - if (g_active_handles < MAX_SESSIONS+2) - { - g_handles[g_active_handles] = handle; - g_active_handles++; - } - else - { - svcCloseHandle(handle); - } - break; + + g_active_handles = 2; + g_cached_prog_handle = 0; + index = 1; + + reply_target = 0; + term_request = 0; + do { + if (reply_target == 0) { + cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0xFFFF0000; } - default: // session - { - handle_commands(); - reply_target = g_handles[index]; - break; + ret = svcReplyAndReceive(&index, g_handles, g_active_handles, + reply_target); + + if (R_FAILED(ret)) { + // check if any handle has been closed + if (ret == (int)0xC920181A) { + if (index == -1) { + for (i = 2; i < MAX_SESSIONS + 2; i++) { + if (g_handles[i] == reply_target) { + index = i; + break; + } + } + } + svcCloseHandle(g_handles[index]); + g_handles[index] = g_handles[g_active_handles - 1]; + g_active_handles--; + reply_target = 0; + } else { + svcBreak(USERBREAK_ASSERT); + } + } else { + // process responses + reply_target = 0; + switch (index) { + case 0: // notification + { + if (R_FAILED(should_terminate(&term_request))) { + svcBreak(USERBREAK_ASSERT); + } + break; + } + case 1: // new session + { + if (R_FAILED(svcAcceptSession(&handle, *srv_handle))) { + svcBreak(USERBREAK_ASSERT); + } + if (g_active_handles < MAX_SESSIONS + 2) { + g_handles[g_active_handles] = handle; + g_active_handles++; + } else { + svcCloseHandle(handle); + } + break; + } + default: // session + { + handle_commands(); + reply_target = g_handles[index]; + break; + } + } } - } - } - } while (!term_request || g_active_handles != 2); + } while (!term_request || g_active_handles != 2); - srvSysUnregisterService("Loader"); - svcCloseHandle(*srv_handle); - svcCloseHandle(*notification_handle); + srvSysUnregisterService("Loader"); + svcCloseHandle(*srv_handle); + svcCloseHandle(*notification_handle); - return 0; + return 0; } diff --git a/external/loader/source/lzss.c b/external/loader/source/lzss.c index 1b1bc0a..a2e508f 100644 --- a/external/loader/source/lzss.c +++ b/external/loader/source/lzss.c @@ -1,55 +1,55 @@ #include <3ds.h> -int lzss_decompress(u8 *buffer) +int +lzss_decompress(u8* buffer) { - // This WAS originally a decompilation in @yifan_lu's repo; it was rewritten for readability following ctrtool's namings. - // You can thank me for making it more readable if you'd like; I don't really care. Did it for myself. - unsigned int decompSize, v15; - u8 *compressEndOff, *index, *stopIndex; - char control; - int v9, v13, v14, v16; - int ret = 0; + // This WAS originally a decompilation in @yifan_lu's repo; it was rewritten + // for readability following ctrtool's namings. + // You can thank me for making it more readable if you'd like; I don't + // really care. Did it for myself. + unsigned int decompSize, v15; + u8 *compressEndOff, *index, *stopIndex; + char control; + int v9, v13, v14, v16; + int ret = 0; - if ( !buffer ) // Return immediately when buffer is invalid. - return 0; + if (!buffer) // Return immediately when buffer is invalid. + return 0; - // v1=decompressedSize, v2=compressedSize, v3=index, v4=stopIndex - decompSize = *((u32 *)buffer - 2); - compressEndOff = &buffer[*((u32 *)buffer - 1)]; - index = &buffer[-(decompSize >> 24)]; // FIXME - The integer negation is due to a compiler optimization. It's probably okay, but... - stopIndex = &buffer[-(decompSize & 0xFFFFFF)]; + // v1=decompressedSize, v2=compressedSize, v3=index, v4=stopIndex + decompSize = *((u32*)buffer - 2); + compressEndOff = &buffer[*((u32*)buffer - 1)]; + index = &buffer[-(decompSize >> 24)]; // FIXME - The integer negation is due + // to a compiler optimization. It's + // probably okay, but... + stopIndex = &buffer[-(decompSize & 0xFFFFFF)]; - while ( index > stopIndex ) // index > stopIndex - { - control = *(index-- - 1); // control (just scoping though) - for (int i=0; i<8; i++) + while (index > stopIndex) // index > stopIndex { - if ( control & 0x80 ) // control & 0x80 - { - v13 = *(index - 1); - v14 = *(index - 2); - index -= 2; - v15 = ((v14 | (v13 << 8)) & 0xFFFF0FFF) + 2; - v16 = v13 + 32; - do - { - ret = compressEndOff[v15]; - *(compressEndOff-- - 1) = ret; - v16 -= 16; + control = *(index-- - 1); // control (just scoping though) + for (int i = 0; i < 8; i++) { + if (control & 0x80) // control & 0x80 + { + v13 = *(index - 1); + v14 = *(index - 2); + index -= 2; + v15 = ((v14 | (v13 << 8)) & 0xFFFF0FFF) + 2; + v16 = v13 + 32; + do { + ret = compressEndOff[v15]; + *(compressEndOff-- - 1) = ret; + v16 -= 16; + } while (!(v16 < 0)); + } else { + v9 = *(index-- - 1); + ret = v9; + *(compressEndOff-- - 1) = v9; + } + control *= 2; + if (index <= stopIndex) + return ret; } - while ( !(v16 < 0) ); - } - else - { - v9 = *(index-- - 1); - ret = v9; - *(compressEndOff-- - 1) = v9; - } - control *= 2; - if ( index <= stopIndex ) - return ret; } - } - return ret; + return ret; } diff --git a/external/loader/source/lzss.h b/external/loader/source/lzss.h index 9e99725..7d71ba4 100644 --- a/external/loader/source/lzss.h +++ b/external/loader/source/lzss.h @@ -1,3 +1,3 @@ #pragma once -int lzss_decompress(u8 *buffer); +int lzss_decompress(u8* buffer); diff --git a/external/loader/source/patch/block_cart_update.c b/external/loader/source/patch/block_cart_update.c index fec2600..06e3adb 100644 --- a/external/loader/source/patch/block_cart_update.c +++ b/external/loader/source/patch/block_cart_update.c @@ -9,16 +9,14 @@ #include "../config.h" #include "../../../../source/patch_format.h" -void disable_cart_updates(u64 progId, u8 *code, u32 size) { - static const u8 stopCartUpdatesPattern[] = {0x0C, 0x18, 0xE1, 0xD8}; - static const u8 stopCartUpdatesPatch[] = {0x0B, 0x18, 0x21, 0xC8}; +void +disable_cart_updates(u64 progId, u8* code, u32 size) +{ + static const u8 stopCartUpdatesPattern[] = { 0x0C, 0x18, 0xE1, 0xD8 }; + static const u8 stopCartUpdatesPatch[] = { 0x0B, 0x18, 0x21, 0xC8 }; - //Disable updates from foreign carts (makes carts region-free) - patchMemory(code, size, - stopCartUpdatesPattern, - sizeof(stopCartUpdatesPattern), 0, - stopCartUpdatesPatch, - sizeof(stopCartUpdatesPatch), 2 - ); + // Disable updates from foreign carts (makes carts region-free) + patchMemory(code, size, stopCartUpdatesPattern, + sizeof(stopCartUpdatesPattern), 0, stopCartUpdatesPatch, + sizeof(stopCartUpdatesPatch), 2); } - diff --git a/external/loader/source/patch/block_eshop_update.c b/external/loader/source/patch/block_eshop_update.c index 0e81795..edcaf31 100644 --- a/external/loader/source/patch/block_eshop_update.c +++ b/external/loader/source/patch/block_eshop_update.c @@ -9,16 +9,16 @@ #include "../config.h" #include "../../../../source/patch_format.h" -void disable_eshop_updates(u64 progId, u8 *code, u32 size) { - static const u8 skipEshopUpdateCheckPattern[] = {0x30, 0xB5, 0xF1, 0xB0}; - static const u8 skipEshopUpdateCheckPatch[] = {0x00, 0x20, 0x08, 0x60, 0x70, 0x47}; +void +disable_eshop_updates(u64 progId, u8* code, u32 size) +{ + static const u8 skipEshopUpdateCheckPattern[] = { 0x30, 0xB5, 0xF1, 0xB0 }; + static const u8 skipEshopUpdateCheckPatch[] = { 0x00, 0x20, 0x08, + 0x60, 0x70, 0x47 }; - //Skip update checks to access the EShop - patchMemory(code, size, - skipEshopUpdateCheckPattern, - sizeof(skipEshopUpdateCheckPattern), 0, - skipEshopUpdateCheckPatch, - sizeof(skipEshopUpdateCheckPatch), 1 - ); + // Skip update checks to access the EShop + patchMemory(code, size, skipEshopUpdateCheckPattern, + sizeof(skipEshopUpdateCheckPattern), 0, + skipEshopUpdateCheckPatch, sizeof(skipEshopUpdateCheckPatch), + 1); } - diff --git a/external/loader/source/patch/block_nim_update.c b/external/loader/source/patch/block_nim_update.c index c9b48ed..682b8f5 100644 --- a/external/loader/source/patch/block_nim_update.c +++ b/external/loader/source/patch/block_nim_update.c @@ -9,16 +9,14 @@ #include "../config.h" #include "../../../../source/patch_format.h" -void disable_nim_updates(u64 progId, u8 *code, u32 size) { - static const u8 blockAutoUpdatesPattern[] = {0x25, 0x79, 0x0B, 0x99}; - static const u8 blockAutoUpdatesPatch[] = {0xE3, 0xA0}; +void +disable_nim_updates(u64 progId, u8* code, u32 size) +{ + static const u8 blockAutoUpdatesPattern[] = { 0x25, 0x79, 0x0B, 0x99 }; + static const u8 blockAutoUpdatesPatch[] = { 0xE3, 0xA0 }; - //Block silent auto-updates - patchMemory(code, size, - blockAutoUpdatesPattern, - sizeof(blockAutoUpdatesPattern), 0, - blockAutoUpdatesPatch, - sizeof(blockAutoUpdatesPatch), 1 - ); + // Block silent auto-updates + patchMemory(code, size, blockAutoUpdatesPattern, + sizeof(blockAutoUpdatesPattern), 0, blockAutoUpdatesPatch, + sizeof(blockAutoUpdatesPatch), 1); } - diff --git a/external/loader/source/patch/friends_ver.c b/external/loader/source/patch/friends_ver.c index bb5a2b8..ac8cfae 100644 --- a/external/loader/source/patch/friends_ver.c +++ b/external/loader/source/patch/friends_ver.c @@ -9,16 +9,14 @@ #include "../config.h" #include "../../../../source/patch_format.h" -void fake_friends_version(u64 progId, u8 *code, u32 size) { - static const u8 fpdVerPattern[] = {0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01}; - static const u8 fpdVerPatch = 0x06; // Latest version. +void +fake_friends_version(u64 progId, u8* code, u32 size) +{ + static const u8 fpdVerPattern[] = { 0xE0, 0x1E, 0xFF, 0x2F, + 0xE1, 0x01, 0x01, 0x01 }; + static const u8 fpdVerPatch = 0x06; // Latest version. - //Allow online access to work with old friends modules - patchMemory(code, size, - fpdVerPattern, - sizeof(fpdVerPattern), 9, - &fpdVerPatch, - sizeof(fpdVerPatch), 1 - ); + // Allow online access to work with old friends modules + patchMemory(code, size, fpdVerPattern, sizeof(fpdVerPattern), 9, + &fpdVerPatch, sizeof(fpdVerPatch), 1); } - diff --git a/external/loader/source/patch/mset_str.c b/external/loader/source/patch/mset_str.c index 949080e..daad227 100644 --- a/external/loader/source/patch/mset_str.c +++ b/external/loader/source/patch/mset_str.c @@ -9,16 +9,13 @@ #include "../config.h" #include "../../../../source/patch_format.h" -void settings_string(u64 progId, u8 *code, u32 size) { - static const u16 verPattern[] = u"Ver."; - static const u16 verPatch[] = u".hax"; +void +settings_string(u64 progId, u8* code, u32 size) +{ + static const u16 verPattern[] = u"Ver."; + static const u16 verPatch[] = u".hax"; - //Patch Ver. string - patchMemory(code, size, - verPattern, - sizeof(verPattern) - sizeof(u16), 0, - verPatch, - sizeof(verPatch) - sizeof(u16), 1 - ); + // Patch Ver. string + patchMemory(code, size, verPattern, sizeof(verPattern) - sizeof(u16), 0, + verPatch, sizeof(verPatch) - sizeof(u16), 1); } - diff --git a/external/loader/source/patch/patch.h b/external/loader/source/patch/patch.h index 1c4be64..2396856 100644 --- a/external/loader/source/patch/patch.h +++ b/external/loader/source/patch/patch.h @@ -1,10 +1,10 @@ #pragma once -void disable_cart_updates(u64 progId, u8 *code, u32 size); -void disable_eshop_updates(u64 progId, u8 *code, u32 size); -void disable_nim_updates(u64 progId, u8 *code, u32 size); -void fake_friends_version(u64 progId, u8 *code, u32 size); -void settings_string(u64 progId, u8 *code, u32 size); -void region_patch(u64 progId, u8 *code, u32 size); -void ro_sigpatch(u64 progId, u8 *code, u32 size); -void secureinfo_sigpatch(u64 progId, u8 *code, u32 size); +void disable_cart_updates(u64 progId, u8* code, u32 size); +void disable_eshop_updates(u64 progId, u8* code, u32 size); +void disable_nim_updates(u64 progId, u8* code, u32 size); +void fake_friends_version(u64 progId, u8* code, u32 size); +void settings_string(u64 progId, u8* code, u32 size); +void region_patch(u64 progId, u8* code, u32 size); +void ro_sigpatch(u64 progId, u8* code, u32 size); +void secureinfo_sigpatch(u64 progId, u8* code, u32 size); diff --git a/external/loader/source/patch/regionfree.c b/external/loader/source/patch/regionfree.c index 16fa192..ee821ce 100644 --- a/external/loader/source/patch/regionfree.c +++ b/external/loader/source/patch/regionfree.c @@ -9,15 +9,15 @@ #include "../config.h" #include "../../../../source/patch_format.h" -void region_patch(u64 progId, u8 *code, u32 size) { - static const u8 regionFreePattern[] = {0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3}; - static const u8 regionFreePatch[] = {0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1}; +void +region_patch(u64 progId, u8* code, u32 size) +{ + static const u8 regionFreePattern[] = { 0x00, 0x00, 0x55, 0xE3, + 0x01, 0x10, 0xA0, 0xE3 }; + static const u8 regionFreePatch[] = { 0x01, 0x00, 0xA0, 0xE3, + 0x1E, 0xFF, 0x2F, 0xE1 }; - //Patch SMDH region checks - patchMemory(code, size, - regionFreePattern, - sizeof(regionFreePattern), -16, - regionFreePatch, - sizeof(regionFreePatch), 1 - ); + // Patch SMDH region checks + patchMemory(code, size, regionFreePattern, sizeof(regionFreePattern), -16, + regionFreePatch, sizeof(regionFreePatch), 1); } diff --git a/external/loader/source/patch/ro_sigs.c b/external/loader/source/patch/ro_sigs.c index 96b85d6..c6c0fd1 100644 --- a/external/loader/source/patch/ro_sigs.c +++ b/external/loader/source/patch/ro_sigs.c @@ -9,34 +9,27 @@ #include "../config.h" #include "../../../../source/patch_format.h" -void ro_sigpatch(u64 progId, u8 *code, u32 size) { - static const u8 sigCheckPattern[] = {0x30, 0x40, 0x2D, 0xE9, 0x02, 0x50, 0xA0, 0xE1}; - static const u8 sha256ChecksPattern1[] = {0x30, 0x40, 0x2D, 0xE9, 0x24, 0xD0, 0x4D, 0xE2}; - static const u8 sha256ChecksPattern2[] = {0xF8, 0x4F, 0x2D, 0xE9, 0x01, 0x70, 0xA0, 0xE1}; +void +ro_sigpatch(u64 progId, u8* code, u32 size) +{ + static const u8 sigCheckPattern[] = { 0x30, 0x40, 0x2D, 0xE9, + 0x02, 0x50, 0xA0, 0xE1 }; + static const u8 sha256ChecksPattern1[] = { 0x30, 0x40, 0x2D, 0xE9, + 0x24, 0xD0, 0x4D, 0xE2 }; + static const u8 sha256ChecksPattern2[] = { 0xF8, 0x4F, 0x2D, 0xE9, + 0x01, 0x70, 0xA0, 0xE1 }; - // mov r0, #0; bx lr - equivalent to 'return 0;' - static const u8 stub[] = {0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1}; + // mov r0, #0; bx lr - equivalent to 'return 0;' + static const u8 stub[] = { 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 }; - //Disable CRR0 signature (RSA2048 with SHA256) check - patchMemory(code, size, - sigCheckPattern, - sizeof(sigCheckPattern), 0, - stub, - sizeof(stub), 1 - ); + // Disable CRR0 signature (RSA2048 with SHA256) check + patchMemory(code, size, sigCheckPattern, sizeof(sigCheckPattern), 0, stub, + sizeof(stub), 1); - //Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table) - patchMemory(code, size, - sha256ChecksPattern1, - sizeof(sha256ChecksPattern1), 0, - stub, - sizeof(stub), 1 - ); + // Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table) + patchMemory(code, size, sha256ChecksPattern1, sizeof(sha256ChecksPattern1), + 0, stub, sizeof(stub), 1); - patchMemory(code, size, - sha256ChecksPattern2, - sizeof(sha256ChecksPattern2), 0, - stub, - sizeof(stub), 1 - ); + patchMemory(code, size, sha256ChecksPattern2, sizeof(sha256ChecksPattern2), + 0, stub, sizeof(stub), 1); } diff --git a/external/loader/source/patch/secinfo_sigs.c b/external/loader/source/patch/secinfo_sigs.c index 3d31237..11b37df 100644 --- a/external/loader/source/patch/secinfo_sigs.c +++ b/external/loader/source/patch/secinfo_sigs.c @@ -9,16 +9,15 @@ #include "../config.h" #include "../../../../source/patch_format.h" -void secureinfo_sigpatch(u64 progId, u8 *code, u32 size) { - static const u8 secureinfoSigCheckPattern[] = {0x06, 0x46, 0x10, 0x48, 0xFC}; - static const u8 secureinfoSigCheckPatch[] = {0x00, 0x26}; +void +secureinfo_sigpatch(u64 progId, u8* code, u32 size) +{ + static const u8 secureinfoSigCheckPattern[] = { 0x06, 0x46, 0x10, 0x48, + 0xFC }; + static const u8 secureinfoSigCheckPatch[] = { 0x00, 0x26 }; - //Disable SecureInfo signature check - patchMemory(code, size, - secureinfoSigCheckPattern, - sizeof(secureinfoSigCheckPattern), 0, - secureinfoSigCheckPatch, - sizeof(secureinfoSigCheckPatch), 1 - ); + // Disable SecureInfo signature check + patchMemory(code, size, secureinfoSigCheckPattern, + sizeof(secureinfoSigCheckPattern), 0, secureinfoSigCheckPatch, + sizeof(secureinfoSigCheckPatch), 1); } - diff --git a/external/loader/source/patcher.c b/external/loader/source/patcher.c index 26c1545..c38e166 100644 --- a/external/loader/source/patcher.c +++ b/external/loader/source/patcher.c @@ -12,39 +12,41 @@ #include "patch/patch.h" -static int memcmp(const void *buf1, const void *buf2, u32 size) +static int +memcmp(const void* buf1, const void* buf2, u32 size) { - const u8 *buf1c = (const u8 *)buf1; - const u8 *buf2c = (const u8 *)buf2; + const u8* buf1c = (const u8*)buf1; + const u8* buf2c = (const u8*)buf2; - for(u32 i = 0; i < size; i++) - { + for (u32 i = 0; i < size; i++) { int cmp = buf1c[i] - buf2c[i]; - if(cmp) return cmp; + if (cmp) + return cmp; } return 0; } -//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 -static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize) +// Quick Search algorithm, adapted from +// http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 +static u8* +memsearch(u8* startPos, const void* pattern, u32 size, u32 patternSize) { - const u8 *patternc = (const u8 *)pattern; + const u8* patternc = (const u8*)pattern; - //Preprocessing + // Preprocessing u32 table[256]; - for(u32 i = 0; i < 256; ++i) + for (u32 i = 0; i < 256; ++i) table[i] = patternSize + 1; - for(u32 i = 0; i < patternSize; ++i) + for (u32 i = 0; i < patternSize; ++i) table[patternc[i]] = patternSize - i; - //Searching + // Searching u32 j = 0; - while(j <= size - patternSize) - { - if(memcmp(patternc, startPos + j, patternSize) == 0) + while (j <= size - patternSize) { + if (memcmp(patternc, startPos + j, patternSize) == 0) return startPos + j; j += table[startPos[j + patternSize]]; } @@ -52,22 +54,25 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz return NULL; } -u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count) +u32 +patchMemory(u8* start, u32 size, const void* pattern, u32 patSize, int offset, + const void* replace, u32 repSize, u32 count) { u32 i; - for(i = 0; i < count; i++) - { - u8 *found = memsearch(start, pattern, size, patSize); + for (i = 0; i < count; i++) { + u8* found = memsearch(start, pattern, size, patSize); - if(found == NULL) break; + if (found == NULL) + break; - // FIXME - This is throwing on Werror. + // FIXME - This is throwing on Werror. memcpy(found + offset, replace, repSize); u32 at = (u32)(found - start); - if(at + patSize > size) break; + if (at + patSize > size) + break; size -= at + patSize; start = found + patSize; @@ -76,177 +81,197 @@ u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offse return i; } -static inline size_t strnlen(const char *string, size_t maxlen) +static inline size_t +strnlen(const char* string, size_t maxlen) { size_t size; - for(size = 0; *string && size < maxlen; string++, size++); + for (size = 0; *string && size < maxlen; string++, size++) + ; return size; } -static int fileOpen(IFile *file, FS_ArchiveID id, const char *path, int flags) +static int +fileOpen(IFile* file, FS_ArchiveID id, const char* path, int flags) { FS_Path apath; FS_Path ppath; apath.type = PATH_EMPTY; apath.size = 1; - apath.data = (u8 *)""; + apath.data = (u8*)""; ppath.type = PATH_ASCII; ppath.data = path; ppath.size = strnlen(path, PATH_MAX) + 1; - return IFile_Open(file, id, apath, ppath, flags); + return IFile_Open(file, id, apath, ppath, flags); } static struct config_file config; static int failed_load_config = 1; -void load_config() { - static IFile file; +void +load_config() +{ + static IFile file; static u64 total; - // Open file. - if (!R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, PATH_CONFIG, FS_OPEN_READ))) { - // Failed to open. + // Open file. + if (!R_SUCCEEDED( + fileOpen(&file, ARCHIVE_SDMC, PATH_CONFIG, FS_OPEN_READ))) { + // Failed to open. return; } - // Read file. - if (!R_SUCCEEDED(IFile_Read(&file, &total, &config, sizeof(struct config_file)))) { - IFile_Close(&file); // Read to memory. + // Read file. + if (!R_SUCCEEDED( + IFile_Read(&file, &total, &config, sizeof(struct config_file)))) { + IFile_Close(&file); // Read to memory. - // Failed to read. - return; - } + // Failed to read. + return; + } - IFile_Close(&file); // Read to memory. + IFile_Close(&file); // Read to memory. - if (config.magic[0] != 'O' || config.magic[1] != 'V' || config.magic[2] != 'A' || config.magic[3] != 'N') { - // Incorrect magic. - // Failed to read. - return; - } + if (config.magic[0] != 'O' || config.magic[1] != 'V' || + config.magic[2] != 'A' || config.magic[3] != 'N') { + // Incorrect magic. + // Failed to read. + return; + } - if (config.config_ver != config_version) { - // Invalid version. - return; + if (config.config_ver != config_version) { + // Invalid version. + return; } - failed_load_config = 0; + failed_load_config = 0; - return; + return; } -static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) +static int +loadTitleLocaleConfig(u64 progId, u8* regionId, u8* languageId) { - // FIXME - Rewrite this function to use a single line-based config + // FIXME - Rewrite this function to use a single line-based config - // Directory seeks have severe issues on FAT and - // dumping configs based on 3dsdb (more than 1000) causes things - // to kinda choke. FAT is not meant for large numbers of files per - // directory due to linear seeks rather than tree or hash-based indexes + // Directory seeks have severe issues on FAT and + // dumping configs based on 3dsdb (more than 1000) causes things + // to kinda choke. FAT is not meant for large numbers of files per + // directory due to linear seeks rather than tree or hash-based indexes char path[] = "/corbenik/etc/locale.conf"; // The locale config file. char progid_str[16]; // Hexdump. - for(int i=0; i < 16; i += 2) { - progid_str[i] = ("0123456789ABCDEF")[ (((u8*)&progId)[0] >> 4) & 0xf ]; - progid_str[i+1] = ("0123456789ABCDEF")[ ((u8*)&progId)[0] & 0xf ]; + for (int i = 0; i < 16; i += 2) { + progid_str[i] = ("0123456789ABCDEF")[(((u8*)&progId)[0] >> 4) & 0xf]; + progid_str[i + 1] = ("0123456789ABCDEF")[((u8*)&progId)[0] & 0xf]; } - static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"}; - static const char *languages[] = {"JA", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"}; + static const char* regions[] = { "JPN", "USA", "EUR", "AUS", + "CHN", "KOR", "TWN" }; + static const char* languages[] = { "JA", "EN", "FR", "DE", "IT", "ES", + "ZH", "KO", "NL", "PT", "RU", "TW" }; IFile file; Result eof = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ); - if(R_SUCCEEDED(eof)) - { + if (R_SUCCEEDED(eof)) { char c; char buf_prog[16]; char country_tmp[16]; char lang_tmp[16]; u64 total; - // TODO - Open and seek file properly + // TODO - Open and seek file properly int i = 0; - int state = 0; // State. 0 = get_titleid, 1 = get_region, 2 = get_language, 3 = process entry - while(1) { - eof = IFile_Read(&file, &total, &c, 1); // Read character. - - if (c == ' ' || c == '\n' || c == '\r' || c == '\t') // Skip space characters. - continue; + int state = 0; // State. 0 = get_titleid, 1 = get_region, 2 = + // get_language, 3 = process entry + while (1) { + eof = IFile_Read(&file, &total, &c, 1); // Read character. + + if (c == ' ' || c == '\n' || c == '\r' || + c == '\t') // Skip space characters. + continue; + + if (c == '#') { // Comment! Skip until a \n or \r. + while (c != '\n' && c != '\r') { + eof = IFile_Read(&file, &total, &c, 1); // Read character. + } + continue; // Resume loop. + } - if (c == '#') { // Comment! Skip until a \n or \r. - while(c != '\n' && c != '\r') { - eof = IFile_Read(&file, &total, &c, 1); // Read character. + switch (state) { + case 0: + // Read titleID. + for (i = 0; i < 16; i++) { + buf_prog[i] = c; + if (i != 15) + eof = IFile_Read(&file, &total, &c, + 1); // Read character. + } + state = 1; + break; + case 1: + // Read country name. Must be <16 chars, past that is + // ignored. + i = 0; + while (c != ' ' && c != '\n' && c != '\r' && + c != '\t') { // While we're not reading a space... + if (i < 15) { + country_tmp[i] = c; + i++; + } + eof = IFile_Read(&file, &total, &c, + 1); // Read character unless last one. + } + state = 2; + break; + case 2: + // Read language name. See country name, code is basically + // identical. + i = 0; + while (c != ' ' && c != '\n' && c != '\r' && + c != '\t') { // While we're not reading a space... + if (i < 15) { // Only read in if <16. + lang_tmp[i] = c; + i++; + } + eof = IFile_Read(&file, &total, &c, + 1); // Read character unless last one. + } + state = 3; + break; + case 3: + // Process entry, return and apply if matched. + if (!memcmp(progid_str, buf_prog, 16)) { + // TitleID matched. Apply language emulation; but first, + // process language and country. + for (i = 0; i < 7; i++) { + if (!memcmp(country_tmp, regions[i], 3)) { + *regionId = (u8)i; + } + } + + for (u32 i = 0; i < 12; i++) { + if (!memcmp(lang_tmp, languages[i], 2)) { + *languageId = (u8)i; + } + } + state = 4; // Processed. Go on. + break; + } + state = 0; // Nope. Move onto the next one. + break; } - continue; // Resume loop. - } - - switch(state) { - case 0: - // Read titleID. - for(i = 0; i < 16; i++) { - buf_prog[i] = c; - if (i != 15) - eof = IFile_Read(&file, &total, &c, 1); // Read character. - } - state = 1; - break; - case 1: - // Read country name. Must be <16 chars, past that is ignored. - i = 0; - while (c != ' ' && c != '\n' && c != '\r' && c != '\t') { // While we're not reading a space... - if (i < 15) { - country_tmp[i] = c; - i++; - } - eof = IFile_Read(&file, &total, &c, 1); // Read character unless last one. - } - state = 2; - break; - case 2: - // Read language name. See country name, code is basically identical. - i = 0; - while (c != ' ' && c != '\n' && c != '\r' && c != '\t') { // While we're not reading a space... - if (i < 15) { // Only read in if <16. - lang_tmp[i] = c; - i++; - } - eof = IFile_Read(&file, &total, &c, 1); // Read character unless last one. - } - state = 3; - break; - case 3: - // Process entry, return and apply if matched. - if(!memcmp(progid_str, buf_prog, 16)) { - // TitleID matched. Apply language emulation; but first, process language and country. - for(i = 0; i < 7; i++) { - if(!memcmp(country_tmp, regions[i], 3)) { - *regionId = (u8)i; - } - } - for(u32 i = 0; i < 12; i++) { - if(!memcmp(lang_tmp, languages[i], 2)) { - *languageId = (u8)i; - } - } - state = 4; // Processed. Go on. + if (!R_SUCCEEDED(eof) || total == 0 || state == 4) break; - } - state = 0; // Nope. Move onto the next one. - break; - } - - if(!R_SUCCEEDED(eof) || total == 0 || state == 4) - break; } } @@ -254,38 +279,41 @@ static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) return eof; } -static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset) +static u8* +getCfgOffsets(u8* code, u32 size, u32* CFGUHandleOffset) { /* HANS: Look for error code which is known to be stored near cfg:u handle this way we can find the right candidate (handle should also be stored right after end of candidate function) */ - u32 n = 0, - possible[24]; + u32 n = 0, possible[24]; - for(u8 *pos = code + 4; n < 24 && pos < code + size - 4; pos += 4) - { - if(*(u32 *)pos == 0xD8A103F9) - { - for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++) - if(*l <= 0x10000000) possible[n++] = *l; + for (u8* pos = code + 4; n < 24 && pos < code + size - 4; pos += 4) { + if (*(u32*)pos == 0xD8A103F9) { + for (u32* l = (u32*)pos - 4; n < 24 && l < (u32*)pos + 4; l++) + if (*l <= 0x10000000) + possible[n++] = *l; } } - for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4) - { - static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082}; + for (u8* CFGU_GetConfigInfoBlk2_endPos = code; + CFGU_GetConfigInfoBlk2_endPos < code + size - 8; + CFGU_GetConfigInfoBlk2_endPos += 4) { + static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = { 0xE8BD8010, + 0x00010082 }; - //There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want - u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos; + // There might be multiple implementations of GetConfigInfoBlk2 but + // let's search for the one we want + u32* cmp = (u32*)CFGU_GetConfigInfoBlk2_endPos; - if(cmp[0] == CFGU_GetConfigInfoBlk2_endPattern[0] && cmp[1] == CFGU_GetConfigInfoBlk2_endPattern[1]) - { - *CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2); + if (cmp[0] == CFGU_GetConfigInfoBlk2_endPattern[0] && + cmp[1] == CFGU_GetConfigInfoBlk2_endPattern[1]) { + *CFGUHandleOffset = *((u32*)CFGU_GetConfigInfoBlk2_endPos + 2); - for(u32 i = 0; i < n; i++) - if(possible[i] == *CFGUHandleOffset) return CFGU_GetConfigInfoBlk2_endPos; + for (u32 i = 0; i < n; i++) + if (possible[i] == *CFGUHandleOffset) + return CFGU_GetConfigInfoBlk2_endPos; CFGU_GetConfigInfoBlk2_endPos += 4; } @@ -294,46 +322,58 @@ static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset) return NULL; } -static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos) +static void +patchCfgGetLanguage(u8* code, u32 size, u8 languageId, + u8* CFGU_GetConfigInfoBlk2_endPos) { - u8 *CFGU_GetConfigInfoBlk2_startPos; //Let's find STMFD SP (there might be a NOP before, but nevermind) - - for(CFGU_GetConfigInfoBlk2_startPos = CFGU_GetConfigInfoBlk2_endPos - 4; - CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D; - CFGU_GetConfigInfoBlk2_startPos -= 2); - - for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4) - { - if(*(u32 *)languageBlkIdPos == 0xA0002) - { - for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough + u8* CFGU_GetConfigInfoBlk2_startPos; // Let's find STMFD SP (there might be + // a NOP before, but nevermind) + + for (CFGU_GetConfigInfoBlk2_startPos = CFGU_GetConfigInfoBlk2_endPos - 4; + CFGU_GetConfigInfoBlk2_startPos >= code && + *((u16*)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D; + CFGU_GetConfigInfoBlk2_startPos -= 2) + ; + + for (u8* languageBlkIdPos = code; languageBlkIdPos < code + size; + languageBlkIdPos += 4) { + if (*(u32*)languageBlkIdPos == 0xA0002) { + for (u8* instr = languageBlkIdPos - 8; + instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; + instr -= 4) // Should be enough { - if(instr[3] == 0xEB) //We're looking for BL + if (instr[3] == 0xEB) // We're looking for BL { - u8 *calledFunction = instr; - u32 i = 0, - found; + u8* calledFunction = instr; + u32 i = 0, found; - do - { - u32 low24 = (*(u32 *)calledFunction & 0x00FFFFFF) << 2; - u32 signMask = (u32)(-(low24 >> 25)) & 0xFC000000; //Sign extension - s32 offset = (s32)(low24 | signMask) + 8; //Branch offset + 8 for prefetch + do { + u32 low24 = (*(u32*)calledFunction & 0x00FFFFFF) << 2; + u32 signMask = (u32)(-(low24 >> 25)) & + 0xFC000000; // Sign extension + s32 offset = (s32)(low24 | signMask) + + 8; // Branch offset + 8 for prefetch calledFunction += offset; - found = calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos; + found = calledFunction >= + CFGU_GetConfigInfoBlk2_startPos - 4 && + calledFunction <= CFGU_GetConfigInfoBlk2_endPos; i++; - } - while(i < 2 && !found && calledFunction[3] == 0xEA); - - if(found) - { - *((u32 *)instr - 1) = 0xE3A00000 | languageId; // mov r0, sp => mov r0, =languageId - *(u32 *)instr = 0xE5CD0000; // bl CFGU_GetConfigInfoBlk2 => strb r0, [sp] - *((u32 *)instr + 1) = 0xE3B00000; // (1 or 2 instructions) => movs r0, 0 (result code) - - //We're done + } while (i < 2 && !found && calledFunction[3] == 0xEA); + + if (found) { + *((u32*)instr - 1) = + 0xE3A00000 | languageId; // mov r0, sp + // => mov r0, =languageId + *(u32*)instr = 0xE5CD0000; // bl + // CFGU_GetConfigInfoBlk2 => + // strb r0, [sp] + *((u32*)instr + 1) = + 0xE3B00000; // (1 or 2 instructions) => movs + // r0, 0 (result code) + + // We're done return; } } @@ -342,92 +382,112 @@ static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetC } } -static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOffset) +static void +patchCfgGetRegion(u8* code, u32 size, u8 regionId, u32 CFGUHandleOffset) { - for(u8 *cmdPos = code; cmdPos < code + size - 28; cmdPos += 4) - { - static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D4F70, 0xE3A00802, 0xE5A40080}; - - u32 *cmp = (u32 *)cmdPos; - - if(cmp[0] == cfgSecureInfoGetRegionCmdPattern[0] && cmp[1] == cfgSecureInfoGetRegionCmdPattern[1] && - cmp[2] == cfgSecureInfoGetRegionCmdPattern[2] && *((u16 *)cmdPos + 7) == 0xE59F && - *(u32 *)(cmdPos + 20 + *((u16 *)cmdPos + 6)) == CFGUHandleOffset) - { - *((u32 *)cmdPos + 4) = 0xE3A00000 | regionId; // mov r0, =regionId - *((u32 *)cmdPos + 5) = 0xE5C40008; // strb r0, [r4, 8] - *((u32 *)cmdPos + 6) = 0xE3B00000; // movs r0, 0 (result code) ('s' not needed but nvm) - *((u32 *)cmdPos + 7) = 0xE5840004; // str r0, [r4, 4] - - //The remaining, not patched, function code will do the rest for us + for (u8* cmdPos = code; cmdPos < code + size - 28; cmdPos += 4) { + static const u32 cfgSecureInfoGetRegionCmdPattern[] = { 0xEE1D4F70, + 0xE3A00802, + 0xE5A40080 }; + + u32* cmp = (u32*)cmdPos; + + if (cmp[0] == cfgSecureInfoGetRegionCmdPattern[0] && + cmp[1] == cfgSecureInfoGetRegionCmdPattern[1] && + cmp[2] == cfgSecureInfoGetRegionCmdPattern[2] && + *((u16*)cmdPos + 7) == 0xE59F && + *(u32*)(cmdPos + 20 + *((u16*)cmdPos + 6)) == CFGUHandleOffset) { + *((u32*)cmdPos + 4) = 0xE3A00000 | regionId; // mov r0, =regionId + *((u32*)cmdPos + 5) = 0xE5C40008; // strb r0, [r4, 8] + *((u32*)cmdPos + 6) = 0xE3B00000; // movs r0, 0 (result + // code) ('s' not needed but nvm) + *((u32*)cmdPos + 7) = 0xE5840004; // str r0, [r4, 4] + + // The remaining, not patched, function code will do the rest for us break; } } } -static void adjust_cpu_settings(u64 progId, u8 *code, u32 size) { - if (!failed_load_config) { - u32 cpuSetting = 0; - // L2 - cpuSetting |= config.options[OPTION_LOADER_CPU_L2]; - // Speed - cpuSetting |= config.options[OPTION_LOADER_CPU_800MHZ] << 1; - - if(cpuSetting) { - static const u8 cfgN3dsCpuPattern[] = {0x00, 0x40, 0xA0, 0xE1, 0x07, 0x00}; - - u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern)); - - //Patch N3DS CPU Clock and L2 cache setting - if(cfgN3dsCpuLoc != NULL) { - *(cfgN3dsCpuLoc + 1) = 0xE1A00000; - *(cfgN3dsCpuLoc + 8) = 0xE3A00000 | cpuSetting; - } - } - } +static void +adjust_cpu_settings(u64 progId, u8* code, u32 size) +{ + if (!failed_load_config) { + u32 cpuSetting = 0; + // L2 + cpuSetting |= config.options[OPTION_LOADER_CPU_L2]; + // Speed + cpuSetting |= config.options[OPTION_LOADER_CPU_800MHZ] << 1; + + if (cpuSetting) { + static const u8 cfgN3dsCpuPattern[] = { 0x00, 0x40, 0xA0, + 0xE1, 0x07, 0x00 }; + + u32* cfgN3dsCpuLoc = (u32*)memsearch(code, cfgN3dsCpuPattern, size, + sizeof(cfgN3dsCpuPattern)); + + // Patch N3DS CPU Clock and L2 cache setting + if (cfgN3dsCpuLoc != NULL) { + *(cfgN3dsCpuLoc + 1) = 0xE1A00000; + *(cfgN3dsCpuLoc + 8) = 0xE3A00000 | cpuSetting; + } + } + } } -void language_emu(u64 progId, u8 *code, u32 size) { - if(!failed_load_config && config.options[OPTION_LOADER_LANGEMU]) { - u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24; - - if(tidHigh == 0x0004000) { // Normal Game - //Language emulation - u8 regionId = 0xFF, - languageId = 0xFF; - - if(R_SUCCEEDED(loadTitleLocaleConfig(progId, ®ionId, &languageId))) { - u32 CFGUHandleOffset; - - u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset); - - if(CFGU_GetConfigInfoBlk2_endPos != NULL) { - if(languageId != 0xFF) - patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos); - if(regionId != 0xFF) - patchCfgGetRegion(code, size, regionId, CFGUHandleOffset); - } - } - } - } +void +language_emu(u64 progId, u8* code, u32 size) +{ + if (!failed_load_config && config.options[OPTION_LOADER_LANGEMU]) { + u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24; + + if (tidHigh == 0x0004000) { // Normal Game + // Language emulation + u8 regionId = 0xFF, languageId = 0xFF; + + if (R_SUCCEEDED( + loadTitleLocaleConfig(progId, ®ionId, &languageId))) { + u32 CFGUHandleOffset; + + u8* CFGU_GetConfigInfoBlk2_endPos = + getCfgOffsets(code, size, &CFGUHandleOffset); + + if (CFGU_GetConfigInfoBlk2_endPos != NULL) { + if (languageId != 0xFF) + patchCfgGetLanguage(code, size, languageId, + CFGU_GetConfigInfoBlk2_endPos); + if (regionId != 0xFF) + patchCfgGetRegion(code, size, regionId, + CFGUHandleOffset); + } + } + } + } } -void overlay_patch(u64 progId, u8 *code, u32 size) { - // TODO - Implement. +void +overlay_patch(u64 progId, u8* code, u32 size) +{ + // TODO - Implement. } // This is only for the .data segment. -void patch_data(u64 progId, u8 *data, u32 size, u32 orig_size) { +void +patch_data(u64 progId, u8* data, u32 size, u32 orig_size) +{ } // This is only for the .ro segment. -void patch_ro(u64 progId, u8 *ro, u32 size, u32 orig_size) { +void +patch_ro(u64 progId, u8* ro, u32 size, u32 orig_size) +{ } // This is only for the .code segment. -void patch_text(u64 progId, u8 *text, u32 size, u32 orig_size) { - switch(progId) - { +void +patch_text(u64 progId, u8* text, u32 size, u32 orig_size) +{ + switch (progId) { case 0x0004003000008F02LL: // USA Menu case 0x0004003000008202LL: // EUR Menu case 0x0004003000009802LL: // JPN Menu @@ -435,20 +495,20 @@ void patch_text(u64 progId, u8 *text, u32 size, u32 orig_size) { case 0x000400300000A902LL: // KOR Menu case 0x000400300000B102LL: // TWN Menu { - region_patch(progId, text, orig_size); + region_patch(progId, text, orig_size); break; } case 0x0004013000002C02LL: // NIM { - disable_nim_updates(progId, text, orig_size); - disable_eshop_updates(progId, text, orig_size); + disable_nim_updates(progId, text, orig_size); + disable_eshop_updates(progId, text, orig_size); break; } case 0x0004013000003202LL: // FRIENDS { - fake_friends_version(progId, text, orig_size); + fake_friends_version(progId, text, orig_size); break; } @@ -459,50 +519,58 @@ void patch_text(u64 progId, u8 *text, u32 size, u32 orig_size) { case 0x0004001000027000LL: // KOR MSET case 0x0004001000028000LL: // TWN MSET { - settings_string(progId, text, size); + settings_string(progId, text, size); break; } case 0x0004013000008002LL: // NS { - disable_cart_updates(progId, text, orig_size); - adjust_cpu_settings(progId, text, orig_size); + disable_cart_updates(progId, text, orig_size); + adjust_cpu_settings(progId, text, orig_size); break; } case 0x0004013000001702LL: // CFG { - secureinfo_sigpatch(progId, text, orig_size); + secureinfo_sigpatch(progId, text, orig_size); + break; + } + case 0x0004013000003702LL: // RO + { + ro_sigpatch(progId, text, orig_size); break; } - case 0x0004013000003702LL: // RO - { - ro_sigpatch(progId, text, orig_size); - break; - } default: // Anything else. - { - language_emu(progId, text, orig_size); + { + language_emu(progId, text, orig_size); break; } } } // Gets how many bytes .text must be extended by for patches to fit. -u32 get_text_extend(u64 progId, u32 size_orig) { - return 0; // Stub - nothing needs this yet +u32 +get_text_extend(u64 progId, u32 size_orig) +{ + return 0; // Stub - nothing needs this yet } // Gets how many bytes .ro must be extended. -u32 get_ro_extend(u64 progId, u32 size_orig) { - return 0; // Stub - nothing needs this yet +u32 +get_ro_extend(u64 progId, u32 size_orig) +{ + return 0; // Stub - nothing needs this yet } // Again, same, but for .data. -u32 get_data_extend(u64 progId, u32 size_orig) { - return 0; // Stub - nothing needs this yet +u32 +get_data_extend(u64 progId, u32 size_orig) +{ + return 0; // Stub - nothing needs this yet } // Get CPU speed for progId. -u8 get_cpumode(u64 progId) { - return 0xff; // Skip. +u8 +get_cpumode(u64 progId) +{ + return 0xff; // Skip. } diff --git a/external/loader/source/patcher.h b/external/loader/source/patcher.h index 5b56b17..2823d47 100644 --- a/external/loader/source/patcher.h +++ b/external/loader/source/patcher.h @@ -2,9 +2,9 @@ #include <3ds/types.h> -void patch_text(u64 progId, u8 *text, u32 size, u32 orig_size); -void patch_data(u64 progId, u8 *data, u32 size, u32 orig_size); -void patch_ro(u64 progId, u8 *ro, u32 size, u32 orig_size); +void patch_text(u64 progId, u8* text, u32 size, u32 orig_size); +void patch_data(u64 progId, u8* data, u32 size, u32 orig_size); +void patch_ro(u64 progId, u8* ro, u32 size, u32 orig_size); u32 get_text_extend(u64 progId, u32 size_orig); u32 get_ro_extend(u64 progId, u32 size_orig); @@ -12,6 +12,7 @@ u32 get_data_extend(u64 progId, u32 size_orig); void load_config(); -u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count); +u32 patchMemory(u8* start, u32 size, const void* pattern, u32 patSize, + int offset, const void* replace, u32 repSize, u32 count); u8 get_cpumode(u64 progId); diff --git a/external/loader/source/pxipm.c b/external/loader/source/pxipm.c index d85d58f..ebeebb4 100644 --- a/external/loader/source/pxipm.c +++ b/external/loader/source/pxipm.c @@ -6,69 +6,81 @@ static Handle pxipmHandle; static int pxipmRefCount; -Result pxipmInit(void) +Result +pxipmInit(void) { - Result ret = 0; + Result ret = 0; - if (AtomicPostIncrement(&pxipmRefCount)) return 0; + if (AtomicPostIncrement(&pxipmRefCount)) + return 0; - ret = srvSysGetServiceHandle(&pxipmHandle, "PxiPM"); + ret = srvSysGetServiceHandle(&pxipmHandle, "PxiPM"); - if (R_FAILED(ret)) AtomicDecrement(&pxipmRefCount); - return ret; + if (R_FAILED(ret)) + AtomicDecrement(&pxipmRefCount); + return ret; } -void pxipmExit(void) +void +pxipmExit(void) { - if (AtomicDecrement(&pxipmRefCount)) return; - svcCloseHandle(pxipmHandle); + if (AtomicDecrement(&pxipmRefCount)) + return; + svcCloseHandle(pxipmHandle); } -Result PXIPM_RegisterProgram(u64 *prog_handle, FS_ProgramInfo *title, FS_ProgramInfo *update) +Result +PXIPM_RegisterProgram(u64* prog_handle, FS_ProgramInfo* title, + FS_ProgramInfo* update) { - u32 *cmdbuf = getThreadCommandBuffer(); - - cmdbuf[0] = IPC_MakeHeader(0x2,8,0); // 0x20200 - memcpy(&cmdbuf[1], &title->programId, sizeof(u64)); - *(u8 *)&cmdbuf[3] = title->mediaType; - memcpy(((u8 *)&cmdbuf[3])+1, &title->padding, 7); - memcpy(&cmdbuf[5], &update->programId, sizeof(u64)); - *(u8 *)&cmdbuf[7] = update->mediaType; - memcpy(((u8 *)&cmdbuf[7])+1, &update->padding, 7); - - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(pxipmHandle))) return ret; - *prog_handle = *(u64*)&cmdbuf[2]; - - return cmdbuf[1]; + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2, 8, 0); // 0x20200 + memcpy(&cmdbuf[1], &title->programId, sizeof(u64)); + *(u8*)&cmdbuf[3] = title->mediaType; + memcpy(((u8*)&cmdbuf[3]) + 1, &title->padding, 7); + memcpy(&cmdbuf[5], &update->programId, sizeof(u64)); + *(u8*)&cmdbuf[7] = update->mediaType; + memcpy(((u8*)&cmdbuf[7]) + 1, &update->padding, 7); + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(pxipmHandle))) + return ret; + *prog_handle = *(u64*)&cmdbuf[2]; + + return cmdbuf[1]; } -Result PXIPM_GetProgramInfo(exheader_header *exheader, u64 prog_handle) +Result +PXIPM_GetProgramInfo(exheader_header* exheader, u64 prog_handle) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x1,2,2); // 0x10082 - cmdbuf[1] = (u32) (prog_handle); - cmdbuf[2] = (u32) (prog_handle >> 32); - cmdbuf[3] = (0x400 << 8) | 0x4; - cmdbuf[4] = (u32) exheader; + cmdbuf[0] = IPC_MakeHeader(0x1, 2, 2); // 0x10082 + cmdbuf[1] = (u32)(prog_handle); + cmdbuf[2] = (u32)(prog_handle >> 32); + cmdbuf[3] = (0x400 << 8) | 0x4; + cmdbuf[4] = (u32)exheader; - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(pxipmHandle))) return ret; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(pxipmHandle))) + return ret; - return cmdbuf[1]; + return cmdbuf[1]; } -Result PXIPM_UnregisterProgram(u64 prog_handle) +Result +PXIPM_UnregisterProgram(u64 prog_handle) { - u32 *cmdbuf = getThreadCommandBuffer(); + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x3,2,0); // 0x30080 - cmdbuf[1] = (u32) (prog_handle); - cmdbuf[2] = (u32) (prog_handle >> 32); + cmdbuf[0] = IPC_MakeHeader(0x3, 2, 0); // 0x30080 + cmdbuf[1] = (u32)(prog_handle); + cmdbuf[2] = (u32)(prog_handle >> 32); - Result ret = 0; - if(R_FAILED(ret = svcSendSyncRequest(pxipmHandle))) return ret; + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(pxipmHandle))) + return ret; - return cmdbuf[1]; + return cmdbuf[1]; } diff --git a/external/loader/source/pxipm.h b/external/loader/source/pxipm.h index e9d1feb..03f48b1 100644 --- a/external/loader/source/pxipm.h +++ b/external/loader/source/pxipm.h @@ -5,6 +5,7 @@ Result pxipmInit(void); void pxipmExit(void); -Result PXIPM_RegisterProgram(u64 *prog_handle, FS_ProgramInfo *title, FS_ProgramInfo *update); -Result PXIPM_GetProgramInfo(exheader_header *exheader, u64 prog_handle); +Result PXIPM_RegisterProgram(u64* prog_handle, FS_ProgramInfo* title, + FS_ProgramInfo* update); +Result PXIPM_GetProgramInfo(exheader_header* exheader, u64 prog_handle); Result PXIPM_UnregisterProgram(u64 prog_handle); diff --git a/external/loader/source/srvsys.c b/external/loader/source/srvsys.c index 1bd05ed..683707d 100644 --- a/external/loader/source/srvsys.c +++ b/external/loader/source/srvsys.c @@ -7,148 +7,162 @@ static int srvRefCount; static RecursiveLock initLock; static int initLockinit = 0; -Result srvSysInit() +Result +srvSysInit() { - Result rc = 0; + Result rc = 0; + + if (!initLockinit) { + RecursiveLock_Init(&initLock); + } + + RecursiveLock_Lock(&initLock); + + if (srvRefCount > 0) { + RecursiveLock_Unlock(&initLock); + return MAKERESULT(RL_INFO, RS_NOP, 25, RD_ALREADY_INITIALIZED); + } + + while (1) { + rc = svcConnectToPort(&srvHandle, "srv:"); + if (R_LEVEL(rc) != RL_PERMANENT || R_SUMMARY(rc) != RS_NOTFOUND || + R_DESCRIPTION(rc) != RD_NOT_FOUND) + break; + svcSleepThread(500000); + } + if (R_SUCCEEDED(rc)) { + rc = srvSysRegisterClient(); + srvRefCount++; + } - if (!initLockinit) - { - RecursiveLock_Init(&initLock); - } - - RecursiveLock_Lock(&initLock); - - if (srvRefCount > 0) - { RecursiveLock_Unlock(&initLock); - return MAKERESULT(RL_INFO, RS_NOP, 25, RD_ALREADY_INITIALIZED); - } - - while (1) - { - rc = svcConnectToPort(&srvHandle, "srv:"); - if (R_LEVEL(rc) != RL_PERMANENT || - R_SUMMARY(rc) != RS_NOTFOUND || - R_DESCRIPTION(rc) != RD_NOT_FOUND - ) break; - svcSleepThread(500000); - } - if (R_SUCCEEDED(rc)) - { - rc = srvSysRegisterClient(); - srvRefCount++; - } - - RecursiveLock_Unlock(&initLock); - return rc; + return rc; } -Result srvSysRegisterClient(void) +Result +srvSysRegisterClient(void) { - Result rc = 0; - u32* cmdbuf = getThreadCommandBuffer(); + Result rc = 0; + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x1,0,2); // 0x10002 - cmdbuf[1] = IPC_Desc_CurProcessHandle(); + cmdbuf[0] = IPC_MakeHeader(0x1, 0, 2); // 0x10002 + cmdbuf[1] = IPC_Desc_CurProcessHandle(); - if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc; + if (R_FAILED(rc = svcSendSyncRequest(srvHandle))) + return rc; - return cmdbuf[1]; + return cmdbuf[1]; } -Result srvSysExit() +Result +srvSysExit() { - Result rc; - RecursiveLock_Lock(&initLock); - - if (srvRefCount > 1) - { + Result rc; + RecursiveLock_Lock(&initLock); + + if (srvRefCount > 1) { + srvRefCount--; + RecursiveLock_Unlock(&initLock); + return MAKERESULT(RL_INFO, RS_NOP, 25, RD_BUSY); + } + + if (srvHandle != 0) + svcCloseHandle(srvHandle); + else + svcBreak(USERBREAK_ASSERT); + rc = (Result)srvHandle; // yeah, I think this is a benign bug + srvHandle = 0; srvRefCount--; RecursiveLock_Unlock(&initLock); - return MAKERESULT(RL_INFO, RS_NOP, 25, RD_BUSY); - } - - if (srvHandle != 0) svcCloseHandle(srvHandle); - else svcBreak(USERBREAK_ASSERT); - rc = (Result)srvHandle; // yeah, I think this is a benign bug - srvHandle = 0; - srvRefCount--; - RecursiveLock_Unlock(&initLock); - return rc; + return rc; } -Result srvSysGetServiceHandle(Handle* out, const char* name) +Result +srvSysGetServiceHandle(Handle* out, const char* name) { - Result rc = 0; - u32* cmdbuf = getThreadCommandBuffer(); + Result rc = 0; + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x5,4,0); // 0x50100 - strncpy((char*) &cmdbuf[1], name,8); - cmdbuf[3] = strlen(name); - cmdbuf[4] = 0x0; + cmdbuf[0] = IPC_MakeHeader(0x5, 4, 0); // 0x50100 + strncpy((char*)&cmdbuf[1], name, 8); + cmdbuf[3] = strlen(name); + cmdbuf[4] = 0x0; - if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc; + if (R_FAILED(rc = svcSendSyncRequest(srvHandle))) + return rc; - if(out) *out = cmdbuf[3]; + if (out) + *out = cmdbuf[3]; - return cmdbuf[1]; + return cmdbuf[1]; } -Result srvSysEnableNotification(Handle* semaphoreOut) +Result +srvSysEnableNotification(Handle* semaphoreOut) { - Result rc = 0; - u32* cmdbuf = getThreadCommandBuffer(); + Result rc = 0; + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x2,0,0); + cmdbuf[0] = IPC_MakeHeader(0x2, 0, 0); - if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc; + if (R_FAILED(rc = svcSendSyncRequest(srvHandle))) + return rc; - if(semaphoreOut) *semaphoreOut = cmdbuf[3]; + if (semaphoreOut) + *semaphoreOut = cmdbuf[3]; - return cmdbuf[1]; + return cmdbuf[1]; } -Result srvSysReceiveNotification(u32* notificationIdOut) +Result +srvSysReceiveNotification(u32* notificationIdOut) { - Result rc = 0; - u32* cmdbuf = getThreadCommandBuffer(); + Result rc = 0; + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0xB,0,0); // 0xB0000 + cmdbuf[0] = IPC_MakeHeader(0xB, 0, 0); // 0xB0000 - if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc; + if (R_FAILED(rc = svcSendSyncRequest(srvHandle))) + return rc; - if(notificationIdOut) *notificationIdOut = cmdbuf[2]; + if (notificationIdOut) + *notificationIdOut = cmdbuf[2]; - return cmdbuf[1]; + return cmdbuf[1]; } -Result srvSysRegisterService(Handle* out, const char* name, int maxSessions) +Result +srvSysRegisterService(Handle* out, const char* name, int maxSessions) { - Result rc = 0; - u32* cmdbuf = getThreadCommandBuffer(); + Result rc = 0; + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x3,4,0); // 0x30100 - strncpy((char*) &cmdbuf[1], name,8); - cmdbuf[3] = strlen(name); - cmdbuf[4] = maxSessions; + cmdbuf[0] = IPC_MakeHeader(0x3, 4, 0); // 0x30100 + strncpy((char*)&cmdbuf[1], name, 8); + cmdbuf[3] = strlen(name); + cmdbuf[4] = maxSessions; - if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc; + if (R_FAILED(rc = svcSendSyncRequest(srvHandle))) + return rc; - if(out) *out = cmdbuf[3]; + if (out) + *out = cmdbuf[3]; - return cmdbuf[1]; + return cmdbuf[1]; } -Result srvSysUnregisterService(const char* name) +Result +srvSysUnregisterService(const char* name) { - Result rc = 0; - u32* cmdbuf = getThreadCommandBuffer(); + Result rc = 0; + u32* cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x4,3,0); // 0x400C0 - strncpy((char*) &cmdbuf[1], name,8); - cmdbuf[3] = strlen(name); + cmdbuf[0] = IPC_MakeHeader(0x4, 3, 0); // 0x400C0 + strncpy((char*)&cmdbuf[1], name, 8); + cmdbuf[3] = strlen(name); - if(R_FAILED(rc = svcSendSyncRequest(srvHandle)))return rc; + if (R_FAILED(rc = svcSendSyncRequest(srvHandle))) + return rc; - return cmdbuf[1]; + return cmdbuf[1]; } diff --git a/external/loader/source/srvsys.h b/external/loader/source/srvsys.h index 7c1c0a8..29a20fb 100644 --- a/external/loader/source/srvsys.h +++ b/external/loader/source/srvsys.h @@ -11,7 +11,8 @@ Result srvSysInit(void); Result srvSysExit(void); /** - * @brief Retrieves a service handle, retrieving from the environment handle list if possible. + * @brief Retrieves a service handle, retrieving from the environment handle + * list if possible. * @param out Pointer to write the handle to. * @param name Name of the service. */ @@ -28,7 +29,8 @@ Result srvSysEnableNotification(Handle* semaphoreOut); /** * @brief Receives a notification. - * @param notificationIdOut Pointer to output the ID of the received notification to. + * @param notificationIdOut Pointer to output the ID of the received + * notification to. */ Result srvSysReceiveNotification(u32* notificationIdOut); diff --git a/source/config.c b/source/config.c index 497a62e..c76583e 100644 --- a/source/config.c +++ b/source/config.c @@ -4,9 +4,11 @@ FILE* conf_handle; struct config_file config; -void regenerate_config() { - f_mkdir(PATH_CFW); - f_mkdir(PATH_CONFIG); +void +regenerate_config() +{ + f_mkdir(PATH_CFW); + f_mkdir(PATH_CONFIG); fprintf(BOTTOM_SCREEN, "Created directory structure.\n"); @@ -14,8 +16,7 @@ void regenerate_config() { memcpy(&(config.magic), CONFIG_MAGIC, 4); config.config_ver = config_version; - - if(!(conf_handle = fopen(PATH_CONFIG, "w"))) + if (!(conf_handle = fopen(PATH_CONFIG, "w"))) abort("Failed to open config for write?\n"); fwrite(&config, 1, sizeof(config), conf_handle); @@ -24,13 +25,15 @@ void regenerate_config() { fprintf(BOTTOM_SCREEN, "Config file written.\n"); } -void load_config() { +void +load_config() +{ // Zero on success. if (!(conf_handle = fopen(PATH_CONFIG, "r"))) { fprintf(BOTTOM_SCREEN, "Config file is missing:\n" " %s\n" "Will create it with defaults.\n", - PATH_CONFIG); + PATH_CONFIG); regenerate_config(); } else { fread(&config, 1, sizeof(config), conf_handle); @@ -42,8 +45,8 @@ void load_config() { "has incorrect magic:\n" " '%c%c%c%c'\n" "Regenerating with defaults.\n", - PATH_CONFIG, - config.magic[0], config.magic[1], config.magic[2], config.magic[3]); + PATH_CONFIG, config.magic[0], config.magic[1], + config.magic[2], config.magic[3]); f_unlink(PATH_CONFIG); regenerate_config(); } @@ -52,22 +55,24 @@ void load_config() { fprintf(BOTTOM_SCREEN, "Config file has outdated version:\n" " %s\n" "Regenerating with defaults.\n", - PATH_CONFIG); + PATH_CONFIG); f_unlink(PATH_CONFIG); regenerate_config(); } } - if (!config.options[OPTION_SILENCE]) - fprintf(BOTTOM_SCREEN, "Config file loaded.\n"); + if (!config.options[OPTION_SILENCE]) + fprintf(BOTTOM_SCREEN, "Config file loaded.\n"); } -void save_config() { - fprintf(stderr, "Saving config.\n"); +void +save_config() +{ + fprintf(stderr, "Saving config.\n"); f_unlink(PATH_CONFIG); - if(!(conf_handle = fopen(PATH_CONFIG, "w"))) + if (!(conf_handle = fopen(PATH_CONFIG, "w"))) abort("Failed to open config for write?\n"); fwrite(&config, 1, sizeof(config), conf_handle); diff --git a/source/config.h b/source/config.h index e972179..a006a13 100644 --- a/source/config.h +++ b/source/config.h @@ -6,57 +6,67 @@ _UNUSED static unsigned int config_version = 1; #define CONFIG_MAGIC "OVAN" // Structure of config file -struct config_file { - char magic[4]; // "OVAN" for shits and giggles again. +struct config_file +{ + char magic[4]; // "OVAN" for shits and giggles again. - uint32_t config_ver; // Config file version. + uint32_t config_ver; // Config file version. - uint8_t options[256]; // Options in the menu - deliberately large to avoid config version bumps. + uint8_t options[256]; // Options in the menu - deliberately large to avoid + // config version bumps. - uint64_t patch_ids[256]; // What patches are enabled by UUID. 256 is an arbitrary limit - contact me if you hit it. -}__attribute__((packed)); + uint64_t patch_ids[256]; // What patches are enabled by UUID. 256 is an + // arbitrary limit - contact me if you hit it. +} __attribute__((packed)); extern struct config_file config; -enum type { - boolean_val, // Toggle - ranged_val, // N1 - N2, left and right to pick. - mask_val // Bitmask allowed values. +enum type +{ + boolean_val, // Toggle + ranged_val, // N1 - N2, left and right to pick. + mask_val // Bitmask allowed values. }; -struct range_str { - int a, b; +struct range_str +{ + int a, b; }; -struct options_s { - int index; - char name[64]; - enum type allowed; - uint32_t a, b; -}__attribute__((packed)); - -#define OPTION_SIGPATCH 0 // Use builtin signature patch. -#define OPTION_FIRMPROT 1 // Protect firmware from writes. -#define OPTION_LOADER 2 // Use builtin loader module replacer. -#define OPTION_SERVICES 3 // Inject services (including backdoor for 11) -#define OPTION_ARM9THREAD 4 // Use builtin ARM9 thread injector. - -#define OPTION_AUTOBOOT 5 // Skip menu unless L is held. -#define OPTION_SILENCE 6 // Don't print debug information. -#define OPTION_TRACE 7 // Pause for A key on each step. - -#define OPTION_TRANSP_BG 8 // Background color is not drawn under text. -#define OPTION_NO_CLEAR_BG 9 // Framebuffer is preserved from whatever ran before us. -#define OPTION_READ_ME 10 // Remove Help/Readme from menu. - -#define OPTION_LOADER_CPU_L2 11 // Enable L2 cache. +struct options_s +{ + int index; + char name[64]; + enum type allowed; + uint32_t a, b; +} __attribute__((packed)); + +#define OPTION_SIGPATCH 0 // Use builtin signature patch. +#define OPTION_FIRMPROT 1 // Protect firmware from writes. +#define OPTION_LOADER 2 // Use builtin loader module replacer. +#define OPTION_SERVICES 3 // Inject services (including backdoor for 11) +#define OPTION_ARM9THREAD 4 // Use builtin ARM9 thread injector. + +#define OPTION_AUTOBOOT 5 // Skip menu unless L is held. +#define OPTION_SILENCE 6 // Don't print debug information. +#define OPTION_TRACE 7 // Pause for A key on each step. + +#define OPTION_TRANSP_BG 8 // Background color is not drawn under text. +#define OPTION_NO_CLEAR_BG \ + 9 // Framebuffer is preserved from whatever ran before us. +#define OPTION_READ_ME 10 // Remove Help/Readme from menu. + +#define OPTION_LOADER_CPU_L2 11 // Enable L2 cache. #define OPTION_LOADER_CPU_800MHZ 12 // Enable 800Mhz mode. -#define OPTION_LOADER_LANGEMU 13 // Enable 800Mhz mode. +#define OPTION_LOADER_LANGEMU 13 // Enable 800Mhz mode. -#define OPTION_REPLACE_ALLOCATED_SVC 14 // Replace allocated services. Normally you don't want this. +#define OPTION_REPLACE_ALLOCATED_SVC \ + 14 // Replace allocated services. Normally you don't want this. -#define IGNORE_PATCH_DEPS 14 // Ignore patch UUID dependencies. Not recommended. -#define IGNORE_BROKEN_SHIT 15 // Allow enabling patches which are marked as 'incompatible'. Chances are there's a reason. +#define IGNORE_PATCH_DEPS 14 // Ignore patch UUID dependencies. Not recommended. +#define IGNORE_BROKEN_SHIT \ + 15 // Allow enabling patches which are marked as 'incompatible'. Chances are + // there's a reason. //#define HEADER_COLOR 12 // Color of header text. //#define BG_COLOR 13 // Color of background. @@ -76,5 +86,4 @@ option_= ... */ - #endif diff --git a/source/fatfs/diskio.c b/source/fatfs/diskio.c index 4edee61..95256a1 100644 --- a/source/fatfs/diskio.c +++ b/source/fatfs/diskio.c @@ -7,112 +7,101 @@ /* storage control modules to the FatFs module with a defined API. */ /*-----------------------------------------------------------------------*/ -#include "diskio.h" /* FatFs lower layer API */ +#include "diskio.h" /* FatFs lower layer API */ #include "sdmmc.h" - /*-----------------------------------------------------------------------*/ /* Get Drive Status */ /*-----------------------------------------------------------------------*/ -DSTATUS disk_status ( - __attribute__((unused)) - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) +DSTATUS +disk_status(__attribute__((unused)) + BYTE pdrv /* Physical drive nmuber to identify the drive */ + ) { - return RES_OK; + return RES_OK; } - - /*-----------------------------------------------------------------------*/ /* Inidialize a Drive */ /*-----------------------------------------------------------------------*/ -DSTATUS disk_initialize ( - __attribute__((unused)) - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) +DSTATUS +disk_initialize(__attribute__((unused)) + BYTE pdrv /* Physical drive nmuber to identify the drive */ + ) { - if (!sdmmc_sdcard_init()) + if (!sdmmc_sdcard_init()) return RES_PARERR; - return RES_OK; + return RES_OK; } - - /*-----------------------------------------------------------------------*/ /* Read Sector(s) */ /*-----------------------------------------------------------------------*/ -DRESULT disk_read ( - __attribute__((unused)) - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - BYTE *buff, /* Data buffer to store read data */ - DWORD sector, /* Sector address in LBA */ - UINT count /* Number of sectors to read */ -) +DRESULT +disk_read(__attribute__((unused)) + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + BYTE* buff, /* Data buffer to store read data */ + DWORD sector, /* Sector address in LBA */ + UINT count /* Number of sectors to read */ + ) { - if (sdmmc_sdcard_readsectors(sector, count, buff)) { - return RES_PARERR; - } + if (sdmmc_sdcard_readsectors(sector, count, buff)) { + return RES_PARERR; + } - return RES_OK; + return RES_OK; } - - /*-----------------------------------------------------------------------*/ /* Write Sector(s) */ /*-----------------------------------------------------------------------*/ #if _USE_WRITE -DRESULT disk_write ( - __attribute__((unused)) - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - const BYTE *buff, /* Data to be written */ - DWORD sector, /* Sector address in LBA */ - UINT count /* Number of sectors to write */ -) +DRESULT +disk_write(__attribute__((unused)) + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + const BYTE* buff, /* Data to be written */ + DWORD sector, /* Sector address in LBA */ + UINT count /* Number of sectors to write */ + ) { - if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) { - return RES_PARERR; - } + if (sdmmc_sdcard_writesectors(sector, count, (BYTE*)buff)) { + return RES_PARERR; + } - return RES_OK; + return RES_OK; } #endif - - /*-----------------------------------------------------------------------*/ /* Miscellaneous Functions */ /*-----------------------------------------------------------------------*/ #if _USE_IOCTL -DRESULT disk_ioctl ( - __attribute__((unused)) - BYTE pdrv, /* Physical drive nmuber (0..) */ - __attribute__((unused)) - BYTE cmd, /* Control code */ - __attribute__((unused)) - void *buff /* Buffer to send/receive control data */ -) +DRESULT +disk_ioctl( + __attribute__((unused)) BYTE pdrv, /* Physical drive nmuber (0..) */ + __attribute__((unused)) BYTE cmd, /* Control code */ + __attribute__((unused)) void* buff /* Buffer to send/receive control data */ + ) { switch (cmd) { case GET_SECTOR_SIZE: - *((DWORD*) buff) = 0x200; + *((DWORD*)buff) = 0x200; return RES_OK; case GET_SECTOR_COUNT: - *((DWORD*) buff) = getMMCDevice(1)->total_size; + *((DWORD*)buff) = getMMCDevice(1)->total_size; return RES_OK; case GET_BLOCK_SIZE: - *((DWORD*) buff) = 0x2000; + *((DWORD*)buff) = 0x2000; return RES_OK; case CTRL_SYNC: // nothing to do here - the disk_write function handles that return RES_OK; } - return RES_PARERR; + return RES_PARERR; } #endif diff --git a/source/fatfs/diskio.h b/source/fatfs/diskio.h index 9ca0c7e..c57983e 100644 --- a/source/fatfs/diskio.h +++ b/source/fatfs/diskio.h @@ -9,69 +9,67 @@ extern "C" { #endif -#define _USE_WRITE 1 /* 1: Enable disk_write function */ -#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */ +#define _USE_WRITE 1 /* 1: Enable disk_write function */ +#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */ #include "integer.h" - /* Status of Disk Functions */ -typedef BYTE DSTATUS; +typedef BYTE DSTATUS; /* Results of Disk Functions */ typedef enum { - RES_OK = 0, /* 0: Successful */ - RES_ERROR, /* 1: R/W Error */ - RES_WRPRT, /* 2: Write Protected */ - RES_NOTRDY, /* 3: Not Ready */ - RES_PARERR /* 4: Invalid Parameter */ + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ } DRESULT; - /*---------------------------------------*/ /* Prototypes for disk control functions */ - -DSTATUS disk_initialize (BYTE pdrv); -DSTATUS disk_status (BYTE pdrv); -DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); -DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); -DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); - +DSTATUS disk_initialize(BYTE pdrv); +DSTATUS disk_status(BYTE pdrv); +DRESULT disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count); +DRESULT disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); +DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff); /* Disk Status Bits (DSTATUS) */ -#define STA_NOINIT 0x01 /* Drive not initialized */ -#define STA_NODISK 0x02 /* No medium in the drive */ -#define STA_PROTECT 0x04 /* Write protected */ - +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ /* Command code for disk_ioctrl fucntion */ /* Generic command (Used by FatFs) */ -#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ -#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ -#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ -#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ -#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ +#define CTRL_SYNC \ + 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ +#define CTRL_TRIM \ + 4 /* Inform device that the data on the block of sectors is no longer used \ + (needed at _USE_TRIM == 1) */ /* Generic command (Not used by FatFs) */ -#define CTRL_POWER 5 /* Get/Set power status */ -#define CTRL_LOCK 6 /* Lock/Unlock media removal */ -#define CTRL_EJECT 7 /* Eject media */ -#define CTRL_FORMAT 8 /* Create physical format on the media */ +#define CTRL_POWER 5 /* Get/Set power status */ +#define CTRL_LOCK 6 /* Lock/Unlock media removal */ +#define CTRL_EJECT 7 /* Eject media */ +#define CTRL_FORMAT 8 /* Create physical format on the media */ /* MMC/SDC specific ioctl command */ -#define MMC_GET_TYPE 10 /* Get card type */ -#define MMC_GET_CSD 11 /* Get CSD */ -#define MMC_GET_CID 12 /* Get CID */ -#define MMC_GET_OCR 13 /* Get OCR */ -#define MMC_GET_SDSTAT 14 /* Get SD status */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ /* ATA/CF specific ioctl command */ -#define ATA_GET_REV 20 /* Get F/W revision */ -#define ATA_GET_MODEL 21 /* Get model name */ -#define ATA_GET_SN 22 /* Get serial number */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ #ifdef __cplusplus } diff --git a/source/fatfs/ff.c b/source/fatfs/ff.c index 41de2fc..ed60fee 100644 --- a/source/fatfs/ff.c +++ b/source/fatfs/ff.c @@ -15,10 +15,8 @@ / by use of this software. /----------------------------------------------------------------------------*/ - -#include "ff.h" /* Declarations of FatFs API */ -#include "diskio.h" /* Declarations of disk I/O functions */ - +#include "ff.h" /* Declarations of FatFs API */ +#include "diskio.h" /* Declarations of disk I/O functions */ /*-------------------------------------------------------------------------- @@ -26,427 +24,660 @@ ---------------------------------------------------------------------------*/ -#if _FATFS != 32020 /* Revision ID */ +#if _FATFS != 32020 /* Revision ID */ #error Wrong include file (ff.h). #endif - /* Reentrancy related */ #if _FS_REENTRANT #if _USE_LFN == 1 #error Static LFN work area cannot be used at thread-safe configuration #endif -#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } -#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#define ENTER_FF(fs) \ + { \ + if (!lock_fs(fs)) \ + return FR_TIMEOUT; \ + } +#define LEAVE_FF(fs, res) \ + { \ + unlock_fs(fs, res); \ + return res; \ + } #else -#define ENTER_FF(fs) -#define LEAVE_FF(fs, res) return res +#define ENTER_FF(fs) +#define LEAVE_FF(fs, res) return res #endif -#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } - +#define ABORT(fs, res) \ + { \ + fp->err = (BYTE)(res); \ + LEAVE_FF(fs, res); \ + } /* Definitions of sector size */ -#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) +#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && \ + _MAX_SS != 2048 && _MAX_SS != 4096) || \ + (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) #error Wrong sector size configuration #endif #if _MAX_SS == _MIN_SS -#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ +#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ #else -#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#define SS(fs) ((fs)->ssize) /* Variable sector size */ #endif - /* Timestamp feature */ #if _FS_NORTC == 1 -#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 +#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || \ + _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 #error Invalid _FS_NORTC settings #endif -#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) +#define GET_FATTIME() \ + ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | \ + (DWORD)_NORTC_MDAY << 16) #else -#define GET_FATTIME() get_fattime() +#define GET_FATTIME() get_fattime() #endif - /* File access control feature */ #if _FS_LOCK #if _FS_READONLY #error _FS_LOCK must be 0 at read-only configuration #endif -typedef struct { - FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ - DWORD clu; /* Object ID 2, directory (0:root) */ - WORD idx; /* Object ID 3, directory index */ - WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +typedef struct +{ + FATFS* fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, directory (0:root) */ + WORD idx; /* Object ID 3, directory index */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, + 0x100:write mode */ } FILESEM; #endif - - /* DBCS code ranges and SBCS extend character conversion table */ -#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ -#define _DF1S 0x81 /* DBC 1st byte range 1 start */ -#define _DF1E 0x9F /* DBC 1st byte range 1 end */ -#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ -#define _DF2E 0xFC /* DBC 1st byte range 2 end */ -#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ -#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ -#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ -#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ - -#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ -#define _DF1S 0x81 -#define _DF1E 0xFE -#define _DS1S 0x40 -#define _DS1E 0x7E -#define _DS2S 0x80 -#define _DS2E 0xFE - -#elif _CODE_PAGE == 949 /* Korean */ -#define _DF1S 0x81 -#define _DF1E 0xFE -#define _DS1S 0x41 -#define _DS1E 0x5A -#define _DS2S 0x61 -#define _DS2E 0x7A -#define _DS3S 0x81 -#define _DS3E 0xFE - -#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ -#define _DF1S 0x81 -#define _DF1E 0xFE -#define _DS1S 0x40 -#define _DS1E 0x7E -#define _DS2S 0xA1 -#define _DS2E 0xFE - -#elif _CODE_PAGE == 437 /* U.S. (OEM) */ -#define _DF1S 0 -/*#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}*/ - -static -const unsigned short Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ - 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, - 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, - 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, - 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, - 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, - 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, - 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, - 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, - 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, - 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, - 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, - 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, - 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, - 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 -}; - -WCHAR ff_convert( /* Converted character, Returns zero on error */ -WCHAR src, /* Character code to be converted */ -UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */ -) +#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ +#define _DF1S 0x81 /* DBC 1st byte range 1 start */ +#define _DF1E 0x9F /* DBC 1st byte range 1 end */ +#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ +#define _DF2E 0xFC /* DBC 1st byte range 2 end */ +#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ +#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ +#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ +#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ + +#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0x80 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 949 /* Korean */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x41 +#define _DS1E 0x5A +#define _DS2S 0x61 +#define _DS2E 0x7A +#define _DS3S 0x81 +#define _DS3E 0xFE + +#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0xA1 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 437 /* U.S. (OEM) */ +#define _DF1S 0 +/*#define _EXCVT + {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, + \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, + \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, + \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}*/ + +static const unsigned short Tbl[] = + { /* CP437(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, + 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C9, 0x00E6, + 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, + 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, + 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, + 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, + 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, + 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, + 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, + 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, + 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, + 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, + 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, + 0x25A0, 0x00A0 + }; + +WCHAR +ff_convert( /* Converted character, Returns zero on error */ + WCHAR src, /* Character code to be converted */ + UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */ + ) { - WCHAR c; - - if(src < 0x80) - { /* ASCII */ - c = src; - } - else - { - if(dir) - { /* OEMCP to Unicode */ - c = (src >= 0x100) ? 0 : Tbl[src - 0x80]; - } - else - { /* Unicode to OEMCP */ - for(c = 0; c < 0x80; c++) - { - if(src == Tbl[c]) - break; - } - c = (c + 0x80) & 0xFF; - } - } - - return c; + WCHAR c; + + if (src < 0x80) { /* ASCII */ + c = src; + } else { + if (dir) { /* OEMCP to Unicode */ + c = (src >= 0x100) ? 0 : Tbl[src - 0x80]; + } else { /* Unicode to OEMCP */ + for (c = 0; c < 0x80; c++) { + if (src == Tbl[c]) + break; + } + c = (c + 0x80) & 0xFF; + } + } + + return c; } -WCHAR ff_wtoupper(WCHAR chr) +WCHAR +ff_wtoupper(WCHAR chr) { - if(chr >= 'a' && chr <= 'z') - return (chr - 32); - else - return chr; + if (chr >= 'a' && chr <= 'z') + return (chr - 32); + else + return chr; } -#elif _CODE_PAGE == 720 /* Arabic (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 737 /* Greek (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ - 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 775 /* Baltic (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ - 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} - -#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ - 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ - 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 857 /* Turkish (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ - 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ - 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 862 /* Hebrew (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 866 /* Russian (OEM) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} - -#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#elif _CODE_PAGE == 720 /* Arabic (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x45, 0x41, 0x84, 0x41, 0x86, 0x43, 0x45, 0x45, 0x45, \ + 0x49, 0x49, 0x8D, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0x93, 0x94, 0x95, \ + 0x49, 0x49, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, \ + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, \ + 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, \ + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 737 /* Greek (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, \ + 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0xAA, 0x92, \ + 0x93, 0x94, 0x95, 0x96, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x97, 0xEA, 0xEB, \ + 0xEC, 0xE4, 0xED, 0xEE, 0xE7, 0xE8, 0xF1, 0xEA, 0xEB, 0xEC, 0xED, \ + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 775 /* Baltic (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x9A, 0x91, 0xA0, 0x8E, 0x95, 0x8F, 0x80, 0xAD, 0xED, 0x8A, \ + 0x8A, 0xA1, 0x8D, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0xE2, 0x99, 0x95, \ + 0x96, 0x97, 0x97, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, \ + 0xA1, 0xE0, 0xA3, 0xA3, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xB5, 0xB6, 0xB7, 0xB8, 0xBD, 0xBE, 0xC6, 0xC7, \ + 0xA5, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, \ + 0xE3, 0xE5, 0xE5, 0xE6, 0xE3, 0xE8, 0xE8, 0xEA, 0xEA, 0xEE, 0xED, \ + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80, 0xD2, 0xD3, 0xD4, \ + 0xD8, 0xD7, 0xDE, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, \ + 0xEA, 0xEB, 0x59, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, 0xB5, \ + 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0x21, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, \ + 0xE3, 0xE5, 0xE5, 0xE6, 0xE7, 0xE7, 0xE9, 0xEA, 0xEB, 0xED, 0xED, \ + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xDE, 0x8F, 0x80, 0x9D, 0xD3, 0x8A, \ + 0x8A, 0xD7, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x91, 0xE2, 0x99, 0x95, \ + 0x95, 0x97, 0x97, 0x99, 0x9A, 0x9B, 0x9B, 0x9D, 0x9E, 0x9F, 0xB5, \ + 0xD6, 0xE0, 0xE9, 0xA4, 0xA4, 0xA6, 0xA6, 0xA8, 0xA8, 0xAA, 0x8D, \ + 0xAC, 0xB8, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBD, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC6, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD1, 0xD1, 0xD2, 0xD3, 0xD2, 0xD5, 0xD6, 0xD7, \ + 0xB7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, \ + 0xE3, 0xE3, 0xD5, 0xE6, 0xE6, 0xE8, 0xE9, 0xE8, 0xEB, 0xED, 0xED, \ + 0xDD, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xEB, 0xFC, 0xFC, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x81, 0x81, 0x83, 0x83, 0x85, 0x85, 0x87, 0x87, 0x89, 0x89, 0x8B, \ + 0x8B, 0x8D, 0x8D, 0x8F, 0x8F, 0x91, 0x91, 0x93, 0x93, 0x95, 0x95, \ + 0x97, 0x97, 0x99, 0x99, 0x9B, 0x9B, 0x9D, 0x9D, 0x9F, 0x9F, 0xA1, \ + 0xA1, 0xA3, 0xA3, 0xA5, 0xA5, 0xA7, 0xA7, 0xA9, 0xA9, 0xAB, 0xAB, \ + 0xAD, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB6, 0xB6, \ + 0xB8, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBE, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD1, 0xD1, 0xD3, 0xD3, 0xD5, 0xD5, 0xD7, 0xD7, \ + 0xDD, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xE0, 0xDF, 0xE0, 0xE2, 0xE2, \ + 0xE4, 0xE4, 0xE6, 0xE6, 0xE8, 0xE8, 0xEA, 0xEA, 0xEC, 0xEC, 0xEE, \ + 0xEE, 0xEF, 0xF0, 0xF2, 0xF2, 0xF4, 0xF4, 0xF6, 0xF6, 0xF8, 0xF8, \ + 0xFA, 0xFA, 0xFC, 0xFC, 0xFD, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 857 /* Turkish (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80, 0xD2, 0xD3, 0xD4, \ + 0xD8, 0xD7, 0x98, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, \ + 0xEA, 0xEB, 0x98, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9E, 0xB5, \ + 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA6, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0x21, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, \ + 0xE3, 0xE5, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xDE, 0x59, \ + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80, 0xD2, 0xD3, 0xD4, \ + 0xD8, 0xD7, 0xDE, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, \ + 0xEA, 0xEB, 0x59, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, 0xB5, \ + 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0x21, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD1, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, \ + 0xE3, 0xE5, 0xE5, 0xE6, 0xE7, 0xE7, 0xE9, 0xEA, 0xEB, 0xED, 0xED, \ + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 862 /* Hebrew (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0x41, \ + 0x49, 0x4F, 0x55, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0x21, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, \ + 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, \ + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 866 /* Russian (OEM) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0x80, \ + 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, \ + 0x8C, 0x8D, 0x8E, 0x8F, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x90, 0x91, 0x92, \ + 0x93, 0x9d, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, \ + 0x9E, 0x9F, 0xF0, 0xF0, 0xF2, 0xF2, 0xF4, 0xF4, 0xF6, 0xF6, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } + +#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, \ + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, \ + 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, \ + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } #elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x8A, 0x9B, 0x8C, 0x8D, 0x8E, 0x8F, 0xA0, \ + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xA3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xA5, 0xAA, 0xBB, 0xBC, 0xBD, 0xBC, 0xAF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0, 0xC1, 0xC2, \ + 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, \ + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8, \ + 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF \ + } #elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ - 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF} +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x82, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x80, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x8A, 0x9B, 0x8C, 0x8D, 0x8E, 0x8F, 0xA0, \ + 0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB2, 0xA5, 0xB5, 0xB6, \ + 0xB7, 0xA8, 0xB9, 0xAA, 0xBB, 0xA3, 0xBD, 0xBD, 0xAF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0, 0xC1, 0xC2, \ + 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, \ + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, \ + 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF \ + } #elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ - 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0xAd, 0x9B, 0x8C, 0x9D, 0xAE, 0x9F, 0xA0, \ + 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0, 0xC1, 0xC2, \ + 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, \ + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8, \ + 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x9F \ + } #elif _CODE_PAGE == 1253 /* Greek (Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \ - 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, \ + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xA2, 0xB8, 0xB9, 0xBA, 0xE0, 0xC1, 0xC2, \ + 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, \ + 0xCE, 0xCF, 0xD0, 0xD1, 0xF2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, \ + 0xD9, 0xDA, 0xFB, 0xBC, 0xFD, 0xBF, 0xFF \ + } #elif _CODE_PAGE == 1254 /* Turkish (Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ - 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x8A, 0x9B, 0x8C, 0x9D, 0x9E, 0x9F, 0xA0, \ + 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0, 0xC1, 0xC2, \ + 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, \ + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8, \ + 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x9F \ + } #elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, \ + 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, \ + 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, \ + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF \ + } #elif _CODE_PAGE == 1256 /* Arabic (Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF} +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x8C, 0x9D, 0x9E, 0x9F, 0xA0, \ + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x41, 0xE1, 0x41, \ + 0xE3, 0xE4, 0xE5, 0xE6, 0x43, 0x45, 0x45, 0x45, 0x45, 0xEC, 0xED, \ + 0x49, 0x49, 0xF0, 0xF1, 0xF2, 0xF3, 0x4F, 0xF5, 0xF6, 0xF7, 0xF8, \ + 0x55, 0xFA, 0x55, 0x55, 0xFD, 0xFE, 0xFF \ + } #elif _CODE_PAGE == 1257 /* Baltic (Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ - 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, \ + 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xA8, 0xB9, 0xAA, 0xBB, 0xBC, 0xBD, 0xBE, 0xAF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0, 0xC1, 0xC2, \ + 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, \ + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8, \ + 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF \ + } #elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */ -#define _DF1S 0 -#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \ - 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ - 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F} - -#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ +#define _DF1S 0 +#define _EXCVT \ + { \ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, \ + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, \ + 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0xAC, 0x9D, 0x9E, 0x9F, 0xA0, \ + 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, \ + 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, \ + 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, \ + 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, \ + 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, \ + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0, 0xC1, 0xC2, \ + 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xEC, 0xCD, \ + 0xCE, 0xCF, 0xD0, 0xD1, 0xF2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8, \ + 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xFE, 0x9F \ + } + +#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ #if _USE_LFN #error Cannot use LFN feature without valid code page. #endif -#define _DF1S 0 +#define _DF1S 0 #else #error Unknown code page #endif - /* Character code support macros */ -#define IsUpper(c) (((c)>='A')&&((c)<='Z')) -#define IsLower(c) (((c)>='a')&&((c)<='z')) -#define IsDigit(c) (((c)>='0')&&((c)<='9')) +#define IsUpper(c) (((c) >= 'A') && ((c) <= 'Z')) +#define IsLower(c) (((c) >= 'a') && ((c) <= 'z')) +#define IsDigit(c) (((c) >= '0') && ((c) <= '9')) -#if _DF1S /* Code page is DBCS */ +#if _DF1S /* Code page is DBCS */ -#ifdef _DF2S /* Two 1st byte areas */ -#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) -#else /* One 1st byte area */ -#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) +#ifdef _DF2S /* Two 1st byte areas */ +#define IsDBCS1(c) \ + (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || \ + ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) +#else /* One 1st byte area */ +#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) #endif -#ifdef _DS3S /* Three 2nd byte areas */ -#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) -#else /* Two 2nd byte areas */ -#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) +#ifdef _DS3S /* Three 2nd byte areas */ +#define IsDBCS2(c) \ + (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || \ + ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || \ + ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) +#else /* Two 2nd byte areas */ +#define IsDBCS2(c) \ + (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || \ + ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) #endif -#else /* Code page is SBCS */ +#else /* Code page is SBCS */ -#define IsDBCS1(c) 0 -#define IsDBCS2(c) 0 +#define IsDBCS1(c) 0 +#define IsDBCS2(c) 0 #endif /* _DF1S */ - /* Name status flags */ -#define NSFLAG 11 /* Index of name status byte in fn[] */ -#define NS_LOSS 0x01 /* Out of 8.3 format */ -#define NS_LFN 0x02 /* Force to create LFN entry */ -#define NS_LAST 0x04 /* Last segment */ -#define NS_BODY 0x08 /* Lower case flag (body) */ -#define NS_EXT 0x10 /* Lower case flag (ext) */ -#define NS_DOT 0x20 /* Dot entry */ - - -/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */ -#define MIN_FAT16 4086U /* Minimum number of clusters as FAT16 */ -#define MIN_FAT32 65526U /* Minimum number of clusters as FAT32 */ - +#define NSFLAG 11 /* Index of name status byte in fn[] */ +#define NS_LOSS 0x01 /* Out of 8.3 format */ +#define NS_LFN 0x02 /* Force to create LFN entry */ +#define NS_LAST 0x04 /* Last segment */ +#define NS_BODY 0x08 /* Lower case flag (body) */ +#define NS_EXT 0x10 /* Lower case flag (ext) */ +#define NS_DOT 0x20 /* Dot entry */ + +/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) + */ +#define MIN_FAT16 4086U /* Minimum number of clusters as FAT16 */ +#define MIN_FAT32 65526U /* Minimum number of clusters as FAT32 */ /* FatFs refers the members in the FAT structures as byte array instead of / structure member because the structure is not binary compatible between / different platforms */ -#define BS_jmpBoot 0 /* x86 jump instruction (3) */ -#define BS_OEMName 3 /* OEM name (8) */ -#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */ -#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */ -#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */ -#define BPB_NumFATs 16 /* Number of FAT copies (1) */ -#define BPB_RootEntCnt 17 /* Number of root directory entries for FAT12/16 (2) */ -#define BPB_TotSec16 19 /* Volume size [sector] (2) */ -#define BPB_Media 21 /* Media descriptor (1) */ -#define BPB_FATSz16 22 /* FAT size [sector] (2) */ -#define BPB_SecPerTrk 24 /* Track size [sector] (2) */ -#define BPB_NumHeads 26 /* Number of heads (2) */ -#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ -#define BPB_TotSec32 32 /* Volume size [sector] (4) */ -#define BS_DrvNum 36 /* Physical drive number (2) */ -#define BS_BootSig 38 /* Extended boot signature (1) */ -#define BS_VolID 39 /* Volume serial number (4) */ -#define BS_VolLab 43 /* Volume label (8) */ -#define BS_FilSysType 54 /* File system type (1) */ -#define BPB_FATSz32 36 /* FAT size [sector] (4) */ -#define BPB_ExtFlags 40 /* Extended flags (2) */ -#define BPB_FSVer 42 /* File system version (2) */ -#define BPB_RootClus 44 /* Root directory first cluster (4) */ -#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ -#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ -#define BS_DrvNum32 64 /* Physical drive number (2) */ -#define BS_BootSig32 66 /* Extended boot signature (1) */ -#define BS_VolID32 67 /* Volume serial number (4) */ -#define BS_VolLab32 71 /* Volume label (8) */ -#define BS_FilSysType32 82 /* File system type (1) */ -#define FSI_LeadSig 0 /* FSI: Leading signature (4) */ -#define FSI_StrucSig 484 /* FSI: Structure signature (4) */ -#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */ -#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */ -#define MBR_Table 446 /* MBR: Partition table offset (2) */ -#define SZ_PTE 16 /* MBR: Size of a partition table entry */ -#define BS_55AA 510 /* Signature word (2) */ - -#define DIR_Name 0 /* Short file name (11) */ -#define DIR_Attr 11 /* Attribute (1) */ -#define DIR_NTres 12 /* Lower case flag (1) */ -#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */ -#define DIR_CrtTime 14 /* Created time (2) */ -#define DIR_CrtDate 16 /* Created date (2) */ -#define DIR_LstAccDate 18 /* Last accessed date (2) */ -#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */ -#define DIR_WrtTime 22 /* Modified time (2) */ -#define DIR_WrtDate 24 /* Modified date (2) */ -#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */ -#define DIR_FileSize 28 /* File size (4) */ -#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ -#define LDIR_Attr 11 /* LFN attribute (1) */ -#define LDIR_Type 12 /* LFN type (1) */ -#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ -#define LDIR_FstClusLO 26 /* Must be zero (0) */ -#define SZ_DIRE 32 /* Size of a directory entry */ -#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ -#define DDEM 0xE5 /* Deleted directory entry mark at DIR_Name[0] */ -#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ - - - +#define BS_jmpBoot 0 /* x86 jump instruction (3) */ +#define BS_OEMName 3 /* OEM name (8) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */ +#define BPB_NumFATs 16 /* Number of FAT copies (1) */ +#define BPB_RootEntCnt \ + 17 /* Number of root directory entries for FAT12/16 (2) */ +#define BPB_TotSec16 19 /* Volume size [sector] (2) */ +#define BPB_Media 21 /* Media descriptor (1) */ +#define BPB_FATSz16 22 /* FAT size [sector] (2) */ +#define BPB_SecPerTrk 24 /* Track size [sector] (2) */ +#define BPB_NumHeads 26 /* Number of heads (2) */ +#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ +#define BPB_TotSec32 32 /* Volume size [sector] (4) */ +#define BS_DrvNum 36 /* Physical drive number (2) */ +#define BS_BootSig 38 /* Extended boot signature (1) */ +#define BS_VolID 39 /* Volume serial number (4) */ +#define BS_VolLab 43 /* Volume label (8) */ +#define BS_FilSysType 54 /* File system type (1) */ +#define BPB_FATSz32 36 /* FAT size [sector] (4) */ +#define BPB_ExtFlags 40 /* Extended flags (2) */ +#define BPB_FSVer 42 /* File system version (2) */ +#define BPB_RootClus 44 /* Root directory first cluster (4) */ +#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ +#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ +#define BS_DrvNum32 64 /* Physical drive number (2) */ +#define BS_BootSig32 66 /* Extended boot signature (1) */ +#define BS_VolID32 67 /* Volume serial number (4) */ +#define BS_VolLab32 71 /* Volume label (8) */ +#define BS_FilSysType32 82 /* File system type (1) */ +#define FSI_LeadSig 0 /* FSI: Leading signature (4) */ +#define FSI_StrucSig 484 /* FSI: Structure signature (4) */ +#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */ +#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */ +#define MBR_Table 446 /* MBR: Partition table offset (2) */ +#define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define BS_55AA 510 /* Signature word (2) */ + +#define DIR_Name 0 /* Short file name (11) */ +#define DIR_Attr 11 /* Attribute (1) */ +#define DIR_NTres 12 /* Lower case flag (1) */ +#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */ +#define DIR_CrtTime 14 /* Created time (2) */ +#define DIR_CrtDate 16 /* Created date (2) */ +#define DIR_LstAccDate 18 /* Last accessed date (2) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */ +#define DIR_WrtTime 22 /* Modified time (2) */ +#define DIR_WrtDate 24 /* Modified date (2) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */ +#define DIR_FileSize 28 /* File size (4) */ +#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ +#define LDIR_Attr 11 /* LFN attribute (1) */ +#define LDIR_Type 12 /* LFN type (1) */ +#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ +#define LDIR_FstClusLO 26 /* Must be zero (0) */ +#define SZ_DIRE 32 /* Size of a directory entry */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ +#define DDEM 0xE5 /* Deleted directory entry mark at DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ /*------------------------------------------------------------*/ /* Module private work area */ @@ -459,3383 +690,3692 @@ WCHAR ff_wtoupper(WCHAR chr) #if _VOLUMES < 1 || _VOLUMES > 9 #error Wrong _VOLUMES setting #endif -static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ -static WORD Fsid; /* File system mount ID */ +static FATFS* + FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ +static WORD Fsid; /* File system mount ID */ #if _FS_RPATH && _VOLUMES >= 2 -static BYTE CurrVol; /* Current drive */ +static BYTE CurrVol; /* Current drive */ #endif #if _FS_LOCK -static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ +static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ #endif -#if _USE_LFN == 0 /* Non LFN feature */ -#define DEFINE_NAMEBUF BYTE sfn[12] -#define INIT_BUF(dobj) (dobj).fn = sfn -#define FREE_BUF() +#if _USE_LFN == 0 /* Non LFN feature */ +#define DEFINE_NAMEBUF BYTE sfn[12] +#define INIT_BUF(dobj) (dobj).fn = sfn +#define FREE_BUF() #else #if _MAX_LFN < 12 || _MAX_LFN > 255 #error Wrong _MAX_LFN setting #endif -#if _USE_LFN == 1 /* LFN feature with static working buffer */ +#if _USE_LFN == 1 /* LFN feature with static working buffer */ static WCHAR LfnBuf[_MAX_LFN + 1]; -#define DEFINE_NAMEBUF BYTE sfn[12] -#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; } -#define FREE_BUF() -#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */ -#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN + 1] -#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; } -#define FREE_BUF() -#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */ -#define DEFINE_NAMEBUF BYTE sfn[12]; WCHAR *lfn -#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); (dobj).lfn = lfn; (dobj).fn = sfn; } -#define FREE_BUF() ff_memfree(lfn) +#define DEFINE_NAMEBUF BYTE sfn[12] +#define INIT_BUF(dobj) \ + { \ + (dobj).fn = sfn; \ + (dobj).lfn = LfnBuf; \ + } +#define FREE_BUF() +#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */ +#define DEFINE_NAMEBUF \ + BYTE sfn[12]; \ + WCHAR lbuf[_MAX_LFN + 1] +#define INIT_BUF(dobj) \ + { \ + (dobj).fn = sfn; \ + (dobj).lfn = lbuf; \ + } +#define FREE_BUF() +#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */ +#define DEFINE_NAMEBUF \ + BYTE sfn[12]; \ + WCHAR* lfn +#define INIT_BUF(dobj) \ + { \ + lfn = ff_memalloc((_MAX_LFN + 1) * 2); \ + if (!lfn) \ + LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \ + (dobj).lfn = lfn; \ + (dobj).fn = sfn; \ + } +#define FREE_BUF() ff_memfree(lfn) #else #error Wrong _USE_LFN setting #endif #endif #ifdef _EXCVT -static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for extended characters */ +static const BYTE ExCvt[] = + _EXCVT; /* Upper conversion table for extended characters */ #endif - - - - - /*-------------------------------------------------------------------------- Module Private Functions ---------------------------------------------------------------------------*/ - /*-----------------------------------------------------------------------*/ /* String functions */ /*-----------------------------------------------------------------------*/ /* Copy memory to memory */ -static -void mem_cpy (void* dst, const void* src, UINT cnt) { - BYTE *d = (BYTE*)dst; - const BYTE *s = (const BYTE*)src; +static void +mem_cpy(void* dst, const void* src, UINT cnt) +{ + BYTE* d = (BYTE*)dst; + const BYTE* s = (const BYTE*)src; #if _WORD_ACCESS == 1 - while (cnt >= sizeof (int)) { - *(int*)d = *(int*)s; - d += sizeof (int); s += sizeof (int); - cnt -= sizeof (int); - } -#endif - while (cnt--) - *d++ = *s++; + while (cnt >= sizeof(int)) { + *(int*)d = *(int*)s; + d += sizeof(int); + s += sizeof(int); + cnt -= sizeof(int); + } +#endif + while (cnt--) + *d++ = *s++; } /* Fill memory */ -static -void mem_set (void* dst, int val, UINT cnt) { - BYTE *d = (BYTE*)dst; +static void +mem_set(void* dst, int val, UINT cnt) +{ + BYTE* d = (BYTE*)dst; - while (cnt--) - *d++ = (BYTE)val; + while (cnt--) + *d++ = (BYTE)val; } /* Compare memory to memory */ -static -int mem_cmp (const void* dst, const void* src, UINT cnt) { - const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; - int r = 0; +static int +mem_cmp(const void* dst, const void* src, UINT cnt) +{ + const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; + int r = 0; - while (cnt-- && (r = *d++ - *s++) == 0) ; - return r; + while (cnt-- && (r = *d++ - *s++) == 0) + ; + return r; } /* Check if chr is contained in the string */ -static -int chk_chr (const char* str, int chr) { - while (*str && *str != chr) str++; - return *str; +static int +chk_chr(const char* str, int chr) +{ + while (*str && *str != chr) + str++; + return *str; } - - - /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ #if _FS_REENTRANT -static -int lock_fs ( - FATFS* fs /* File system object */ -) +static int +lock_fs(FATFS* fs /* File system object */ + ) { - return ff_req_grant(fs->sobj); + return ff_req_grant(fs->sobj); } - -static -void unlock_fs ( - FATFS* fs, /* File system object */ - FRESULT res /* Result code to be returned */ -) +static void +unlock_fs(FATFS* fs, /* File system object */ + FRESULT res /* Result code to be returned */ + ) { - if (fs && - res != FR_NOT_ENABLED && - res != FR_INVALID_DRIVE && - res != FR_INVALID_OBJECT && - res != FR_TIMEOUT) { - ff_rel_grant(fs->sobj); - } + if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && + res != FR_INVALID_OBJECT && res != FR_TIMEOUT) { + ff_rel_grant(fs->sobj); + } } #endif - - - /*-----------------------------------------------------------------------*/ /* File lock control functions */ /*-----------------------------------------------------------------------*/ #if _FS_LOCK -static -FRESULT chk_lock ( /* Check if the file can be accessed */ - DIR* dp, /* Directory object pointing the file to be checked */ - int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */ -) +static FRESULT +chk_lock( /* Check if the file can be accessed */ + DIR* dp, /* Directory object pointing the file to be checked */ + int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */ + ) { - UINT i, be; - - /* Search file semaphore table */ - for (i = be = 0; i < _FS_LOCK; i++) { - if (Files[i].fs) { /* Existing entry */ - if (Files[i].fs == dp->fs && /* Check if the object matched with an open object */ - Files[i].clu == dp->sclust && - Files[i].idx == dp->index) break; - } else { /* Blank entry */ - be = 1; - } - } - if (i == _FS_LOCK) /* The object is not opened */ - return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ - - /* The object has been opened. Reject any open against writing file and all write mode open */ - return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; + UINT i, be; + + /* Search file semaphore table */ + for (i = be = 0; i < _FS_LOCK; i++) { + if (Files[i].fs) { /* Existing entry */ + if (Files[i].fs == + dp + ->fs && /* Check if the object matched with an open + object */ + Files[i].clu == dp->sclust && + Files[i].idx == dp->index) + break; + } else { /* Blank entry */ + be = 1; + } + } + if (i == _FS_LOCK) /* The object is not opened */ + return (be || acc == 2) ? FR_OK + : FR_TOO_MANY_OPEN_FILES; /* Is there a blank + entry for new + object? */ + + /* The object has been opened. Reject any open against writing file and all + * write mode open */ + return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; } - -static -int enq_lock (void) /* Check if an entry is available for a new object */ +static int enq_lock(void) /* Check if an entry is available for a new object */ { - UINT i; + UINT i; - for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; - return (i == _FS_LOCK) ? 0 : 1; + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) + ; + return (i == _FS_LOCK) ? 0 : 1; } - -static -UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ - DIR* dp, /* Directory object pointing the file to register or increment */ - int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ -) +static UINT +inc_lock(/* Increment object open counter and returns its index (0:Internal + error) */ + DIR* + dp, /* Directory object pointing the file to register or increment + */ + int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ + ) { - UINT i; - - - for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ - if (Files[i].fs == dp->fs && - Files[i].clu == dp->sclust && - Files[i].idx == dp->index) break; - } - - if (i == _FS_LOCK) { /* Not opened. Register it as new. */ - for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; - if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ - Files[i].fs = dp->fs; - Files[i].clu = dp->sclust; - Files[i].idx = dp->index; - Files[i].ctr = 0; - } - - if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ - - Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ - - return i + 1; + UINT i; + + for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ + if (Files[i].fs == dp->fs && Files[i].clu == dp->sclust && + Files[i].idx == dp->index) + break; + } + + if (i == _FS_LOCK) { /* Not opened. Register it as new. */ + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) + ; + if (i == _FS_LOCK) + return 0; /* No free entry to register (int err) */ + Files[i].fs = dp->fs; + Files[i].clu = dp->sclust; + Files[i].idx = dp->index; + Files[i].ctr = 0; + } + + if (acc && Files[i].ctr) + return 0; /* Access violation (int err) */ + + Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ + + return i + 1; } - -static -FRESULT dec_lock ( /* Decrement object open counter */ - UINT i /* Semaphore index (1..) */ -) +static FRESULT +dec_lock( /* Decrement object open counter */ + UINT i /* Semaphore index (1..) */ + ) { - WORD n; - FRESULT res; - - - if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ - n = Files[i].ctr; - if (n == 0x100) n = 0; /* If write mode open, delete the entry */ - if (n) n--; /* Decrement read mode open count */ - Files[i].ctr = n; - if (!n) Files[i].fs = 0; /* Delete the entry if open count gets zero */ - res = FR_OK; - } else { - res = FR_INT_ERR; /* Invalid index nunber */ - } - return res; + WORD n; + FRESULT res; + + if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ + n = Files[i].ctr; + if (n == 0x100) + n = 0; /* If write mode open, delete the entry */ + if (n) + n--; /* Decrement read mode open count */ + Files[i].ctr = n; + if (!n) + Files[i].fs = 0; /* Delete the entry if open count gets zero */ + res = FR_OK; + } else { + res = FR_INT_ERR; /* Invalid index nunber */ + } + return res; } - -static -void clear_lock ( /* Clear lock entries of the volume */ - FATFS *fs -) +static void +clear_lock(/* Clear lock entries of the volume */ + FATFS* fs) { - UINT i; + UINT i; - for (i = 0; i < _FS_LOCK; i++) { - if (Files[i].fs == fs) Files[i].fs = 0; - } + for (i = 0; i < _FS_LOCK; i++) { + if (Files[i].fs == fs) + Files[i].fs = 0; + } } #endif - - - /*-----------------------------------------------------------------------*/ /* Move/Flush disk access window in the file system object */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY -static -FRESULT sync_window ( - FATFS* fs /* File system object */ -) +static FRESULT +sync_window(FATFS* fs /* File system object */ + ) { - DWORD wsect; - UINT nf; - FRESULT res = FR_OK; - - - if (fs->wflag) { /* Write back the sector if it is dirty */ - wsect = fs->winsect; /* Current sector number */ - if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) { - res = FR_DISK_ERR; - } else { - fs->wflag = 0; - if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */ - for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */ - wsect += fs->fsize; - disk_write(fs->drv, fs->win, wsect, 1); - } - } - } - } - return res; + DWORD wsect; + UINT nf; + FRESULT res = FR_OK; + + if (fs->wflag) { /* Write back the sector if it is dirty */ + wsect = fs->winsect; /* Current sector number */ + if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fs->wflag = 0; + if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */ + for (nf = fs->n_fats; nf >= 2; + nf--) { /* Reflect the change to all FAT copies */ + wsect += fs->fsize; + disk_write(fs->drv, fs->win, wsect, 1); + } + } + } + } + return res; } #endif - -static -FRESULT move_window ( - FATFS* fs, /* File system object */ - DWORD sector /* Sector number to make appearance in the fs->win[] */ -) +static FRESULT +move_window(FATFS* fs, /* File system object */ + DWORD sector /* Sector number to make appearance in the fs->win[] */ + ) { - FRESULT res = FR_OK; + FRESULT res = FR_OK; - - if (sector != fs->winsect) { /* Window offset changed? */ + if (sector != fs->winsect) { /* Window offset changed? */ #if !_FS_READONLY - res = sync_window(fs); /* Write-back changes */ -#endif - if (res == FR_OK) { /* Fill sector window with new data */ - if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) { - sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */ - res = FR_DISK_ERR; - } - fs->winsect = sector; - } - } - return res; + res = sync_window(fs); /* Write-back changes */ +#endif + if (res == FR_OK) { /* Fill sector window with new data */ + if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) { + sector = + 0xFFFFFFFF; /* Invalidate window if data is not reliable */ + res = FR_DISK_ERR; + } + fs->winsect = sector; + } + } + return res; } - - - /*-----------------------------------------------------------------------*/ /* Synchronize file system and strage device */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY -static -FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ - FATFS* fs /* File system object */ -) +static FRESULT +sync_fs( /* FR_OK: successful, FR_DISK_ERR: failed */ + FATFS* fs /* File system object */ + ) { - FRESULT res; - - - res = sync_window(fs); - if (res == FR_OK) { - /* Update FSINFO sector if needed */ - if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { - /* Create FSINFO structure */ - mem_set(fs->win, 0, SS(fs)); - ST_WORD(fs->win + BS_55AA, 0xAA55); - ST_DWORD(fs->win + FSI_LeadSig, 0x41615252); - ST_DWORD(fs->win + FSI_StrucSig, 0x61417272); - ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust); - ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust); - /* Write it into the FSINFO sector */ - fs->winsect = fs->volbase + 1; - disk_write(fs->drv, fs->win, fs->winsect, 1); - fs->fsi_flag = 0; - } - /* Make sure that no pending write process in the physical drive */ - if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) - res = FR_DISK_ERR; - } - - return res; + FRESULT res; + + res = sync_window(fs); + if (res == FR_OK) { + /* Update FSINFO sector if needed */ + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { + /* Create FSINFO structure */ + mem_set(fs->win, 0, SS(fs)); + ST_WORD(fs->win + BS_55AA, 0xAA55); + ST_DWORD(fs->win + FSI_LeadSig, 0x41615252); + ST_DWORD(fs->win + FSI_StrucSig, 0x61417272); + ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust); + ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust); + /* Write it into the FSINFO sector */ + fs->winsect = fs->volbase + 1; + disk_write(fs->drv, fs->win, fs->winsect, 1); + fs->fsi_flag = 0; + } + /* Make sure that no pending write process in the physical drive */ + if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) + res = FR_DISK_ERR; + } + + return res; } #endif - - - /*-----------------------------------------------------------------------*/ /* Get sector# from cluster# */ /*-----------------------------------------------------------------------*/ /* Hidden API for hacks and disk tools */ -DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ - FATFS* fs, /* File system object */ - DWORD clst /* Cluster# to be converted */ -) +DWORD +clust2sect( /* !=0: Sector number, 0: Failed - invalid cluster# */ + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to be converted */ + ) { - clst -= 2; - if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */ - return clst * fs->csize + fs->database; + clst -= 2; + if (clst >= fs->n_fatent - 2) + return 0; /* Invalid cluster# */ + return clst * fs->csize + fs->database; } - - - /*-----------------------------------------------------------------------*/ /* FAT access - Read value of a FAT entry */ /*-----------------------------------------------------------------------*/ /* Hidden API for hacks and disk tools */ -DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */ - FATFS* fs, /* File system object */ - DWORD clst /* FAT index number (cluster number) to get the value */ -) +DWORD +get_fat(/* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status + */ + FATFS* fs, /* File system object */ + DWORD clst /* FAT index number (cluster number) to get the value */ + ) { - UINT wc, bc; - BYTE *p; - DWORD val; - - - if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ - val = 1; /* Internal error */ - - } else { - val = 0xFFFFFFFF; /* Default value falls on disk error */ - - switch (fs->fs_type) { - case FS_FAT12 : - bc = (UINT)clst; bc += bc / 2; - if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; - wc = fs->win[bc++ % SS(fs)]; - if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; - wc |= fs->win[bc % SS(fs)] << 8; - val = clst & 1 ? wc >> 4 : (wc & 0xFFF); - break; - - case FS_FAT16 : - if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; - p = &fs->win[clst * 2 % SS(fs)]; - val = LD_WORD(p); - break; - - case FS_FAT32 : - if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - p = &fs->win[clst * 4 % SS(fs)]; - val = LD_DWORD(p) & 0x0FFFFFFF; - break; - - default: - val = 1; /* Internal error */ - } - } - - return val; + UINT wc, bc; + BYTE* p; + DWORD val; + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + val = 1; /* Internal error */ + + } else { + val = 0xFFFFFFFF; /* Default value falls on disk error */ + + switch (fs->fs_type) { + case FS_FAT12: + bc = (UINT)clst; + bc += bc / 2; + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) + break; + wc = fs->win[bc++ % SS(fs)]; + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) + break; + wc |= fs->win[bc % SS(fs)] << 8; + val = clst & 1 ? wc >> 4 : (wc & 0xFFF); + break; + + case FS_FAT16: + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != + FR_OK) + break; + p = &fs->win[clst * 2 % SS(fs)]; + val = LD_WORD(p); + break; + + case FS_FAT32: + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != + FR_OK) + break; + p = &fs->win[clst * 4 % SS(fs)]; + val = LD_DWORD(p) & 0x0FFFFFFF; + break; + + default: + val = 1; /* Internal error */ + } + } + + return val; } - - - /*-----------------------------------------------------------------------*/ /* FAT access - Change value of a FAT entry */ /*-----------------------------------------------------------------------*/ /* Hidden API for hacks and disk tools */ #if !_FS_READONLY -FRESULT put_fat ( - FATFS* fs, /* File system object */ - DWORD clst, /* FAT index number (cluster number) to be changed */ - DWORD val /* New value to be set to the entry */ -) +FRESULT +put_fat(FATFS* fs, /* File system object */ + DWORD clst, /* FAT index number (cluster number) to be changed */ + DWORD val /* New value to be set to the entry */ + ) { - UINT bc; - BYTE *p; - FRESULT res; - - - if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ - res = FR_INT_ERR; - - } else { - switch (fs->fs_type) { - case FS_FAT12 : - bc = (UINT)clst; bc += bc / 2; - res = move_window(fs, fs->fatbase + (bc / SS(fs))); - if (res != FR_OK) break; - p = &fs->win[bc++ % SS(fs)]; - *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; - fs->wflag = 1; - res = move_window(fs, fs->fatbase + (bc / SS(fs))); - if (res != FR_OK) break; - p = &fs->win[bc % SS(fs)]; - *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); - fs->wflag = 1; - break; - - case FS_FAT16 : - res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); - if (res != FR_OK) break; - p = &fs->win[clst * 2 % SS(fs)]; - ST_WORD(p, (WORD)val); - fs->wflag = 1; - break; - - case FS_FAT32 : - res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); - if (res != FR_OK) break; - p = &fs->win[clst * 4 % SS(fs)]; - val |= LD_DWORD(p) & 0xF0000000; - ST_DWORD(p, val); - fs->wflag = 1; - break; - - default : - res = FR_INT_ERR; - } - } - - return res; + UINT bc; + BYTE* p; + FRESULT res; + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + res = FR_INT_ERR; + + } else { + switch (fs->fs_type) { + case FS_FAT12: + bc = (UINT)clst; + bc += bc / 2; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) + break; + p = &fs->win[bc++ % SS(fs)]; + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; + fs->wflag = 1; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) + break; + p = &fs->win[bc % SS(fs)]; + *p = (clst & 1) ? (BYTE)(val >> 4) + : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); + fs->wflag = 1; + break; + + case FS_FAT16: + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); + if (res != FR_OK) + break; + p = &fs->win[clst * 2 % SS(fs)]; + ST_WORD(p, (WORD)val); + fs->wflag = 1; + break; + + case FS_FAT32: + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); + if (res != FR_OK) + break; + p = &fs->win[clst * 4 % SS(fs)]; + val |= LD_DWORD(p) & 0xF0000000; + ST_DWORD(p, val); + fs->wflag = 1; + break; + + default: + res = FR_INT_ERR; + } + } + + return res; } #endif /* !_FS_READONLY */ - - - /*-----------------------------------------------------------------------*/ /* FAT handling - Remove a cluster chain */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY -static -FRESULT remove_chain ( - FATFS* fs, /* File system object */ - DWORD clst /* Cluster# to remove a chain from */ -) +static FRESULT +remove_chain(FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to remove a chain from */ + ) { - FRESULT res; - DWORD nxt; + FRESULT res; + DWORD nxt; #if _USE_TRIM - DWORD scl = clst, ecl = clst, rt[2]; -#endif - - if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ - res = FR_INT_ERR; - - } else { - res = FR_OK; - while (clst < fs->n_fatent) { /* Not a last link? */ - nxt = get_fat(fs, clst); /* Get cluster status */ - if (nxt == 0) break; /* Empty cluster? */ - if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */ - if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */ - res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */ - if (res != FR_OK) break; - if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */ - fs->free_clust++; - fs->fsi_flag |= 1; - } + DWORD scl = clst, ecl = clst, rt[2]; +#endif + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + res = FR_INT_ERR; + + } else { + res = FR_OK; + while (clst < fs->n_fatent) { /* Not a last link? */ + nxt = get_fat(fs, clst); /* Get cluster status */ + if (nxt == 0) + break; /* Empty cluster? */ + if (nxt == 1) { + res = FR_INT_ERR; + break; + } /* Internal error? */ + if (nxt == 0xFFFFFFFF) { + res = FR_DISK_ERR; + break; + } /* Disk error? */ + res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */ + if (res != FR_OK) + break; + if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */ + fs->free_clust++; + fs->fsi_flag |= 1; + } #if _USE_TRIM - if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ - ecl = nxt; - } else { /* End of contiguous clusters */ - rt[0] = clust2sect(fs, scl); /* Start sector */ - rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ - disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Erase the block */ - scl = ecl = nxt; - } -#endif - clst = nxt; /* Next cluster */ - } - } - - return res; + if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ + ecl = nxt; + } else { /* End of contiguous clusters */ + rt[0] = clust2sect(fs, scl); /* Start sector */ + rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ + disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Erase the block */ + scl = ecl = nxt; + } +#endif + clst = nxt; /* Next cluster */ + } + } + + return res; } #endif - - - /*-----------------------------------------------------------------------*/ /* FAT handling - Stretch or Create a cluster chain */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY -static -DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ - FATFS* fs, /* File system object */ - DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ -) +static DWORD +create_chain(/* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, + >=2:New cluster# */ + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ + ) { - DWORD cs, ncl, scl; - FRESULT res; - - - if (clst == 0) { /* Create a new chain */ - scl = fs->last_clust; /* Get suggested start point */ - if (!scl || scl >= fs->n_fatent) scl = 1; - } - else { /* Stretch the current chain */ - cs = get_fat(fs, clst); /* Check the cluster status */ - if (cs < 2) return 1; /* Invalid value */ - if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ - if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ - scl = clst; - } - - ncl = scl; /* Start cluster */ - for (;;) { - ncl++; /* Next cluster */ - if (ncl >= fs->n_fatent) { /* Check wrap around */ - ncl = 2; - if (ncl > scl) return 0; /* No free cluster */ - } - cs = get_fat(fs, ncl); /* Get the cluster status */ - if (cs == 0) break; /* Found a free cluster */ - if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */ - return cs; - if (ncl == scl) return 0; /* No free cluster */ - } - - res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */ - if (res == FR_OK && clst != 0) { - res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */ - } - if (res == FR_OK) { - fs->last_clust = ncl; /* Update FSINFO */ - if (fs->free_clust != 0xFFFFFFFF) { - fs->free_clust--; - fs->fsi_flag |= 1; - } - } else { - ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; - } - - return ncl; /* Return new cluster number or error code */ + DWORD cs, ncl, scl; + FRESULT res; + + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clust; /* Get suggested start point */ + if (!scl || scl >= fs->n_fatent) + scl = 1; + } else { /* Stretch the current chain */ + cs = get_fat(fs, clst); /* Check the cluster status */ + if (cs < 2) + return 1; /* Invalid value */ + if (cs == 0xFFFFFFFF) + return cs; /* A disk error occurred */ + if (cs < fs->n_fatent) + return cs; /* It is already followed by next cluster */ + scl = clst; + } + + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap around */ + ncl = 2; + if (ncl > scl) + return 0; /* No free cluster */ + } + cs = get_fat(fs, ncl); /* Get the cluster status */ + if (cs == 0) + break; /* Found a free cluster */ + if (cs == 0xFFFFFFFF || cs == 1) /* An error occurred */ + return cs; + if (ncl == scl) + return 0; /* No free cluster */ + } + + res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */ + if (res == FR_OK && clst != 0) { + res = + put_fat(fs, clst, ncl); /* Link it to the previous one if needed */ + } + if (res == FR_OK) { + fs->last_clust = ncl; /* Update FSINFO */ + if (fs->free_clust != 0xFFFFFFFF) { + fs->free_clust--; + fs->fsi_flag |= 1; + } + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; + } + + return ncl; /* Return new cluster number or error code */ } #endif /* !_FS_READONLY */ - - - /*-----------------------------------------------------------------------*/ /* FAT handling - Convert offset into cluster with link map table */ /*-----------------------------------------------------------------------*/ #if _USE_FASTSEEK -static -DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ - FIL* fp, /* Pointer to the file object */ - DWORD ofs /* File offset to be converted to cluster# */ -) +static DWORD +clmt_clust( /* <2:Error, >=2:Cluster number */ + FIL* fp, /* Pointer to the file object */ + DWORD ofs /* File offset to be converted to cluster# */ + ) { - DWORD cl, ncl, *tbl; - - - tbl = fp->cltbl + 1; /* Top of CLMT */ - cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */ - for (;;) { - ncl = *tbl++; /* Number of cluters in the fragment */ - if (!ncl) return 0; /* End of table? (error) */ - if (cl < ncl) break; /* In this fragment? */ - cl -= ncl; tbl++; /* Next fragment */ - } - return cl + *tbl; /* Return the cluster number */ + DWORD cl, ncl, *tbl; + + tbl = fp->cltbl + 1; /* Top of CLMT */ + cl = ofs / SS(fp->fs) / + fp->fs->csize; /* Cluster order from top of the file */ + for (;;) { + ncl = *tbl++; /* Number of cluters in the fragment */ + if (!ncl) + return 0; /* End of table? (error) */ + if (cl < ncl) + break; /* In this fragment? */ + cl -= ncl; + tbl++; /* Next fragment */ + } + return cl + *tbl; /* Return the cluster number */ } -#endif /* _USE_FASTSEEK */ - - - +#endif /* _USE_FASTSEEK */ /*-----------------------------------------------------------------------*/ /* Directory handling - Set directory index */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_sdi ( - DIR* dp, /* Pointer to directory object */ - UINT idx /* Index of directory table */ -) +static FRESULT +dir_sdi(DIR* dp, /* Pointer to directory object */ + UINT idx /* Index of directory table */ + ) { - DWORD clst, sect; - UINT ic; - - - dp->index = (WORD)idx; /* Current index */ - clst = dp->sclust; /* Table start cluster (0:root) */ - if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */ - return FR_INT_ERR; - if (!clst && dp->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ - clst = dp->fs->dirbase; - - if (clst == 0) { /* Static table (root-directory in FAT12/16) */ - if (idx >= dp->fs->n_rootdir) /* Is index out of range? */ - return FR_INT_ERR; - sect = dp->fs->dirbase; - } - else { /* Dynamic table (root-directory in FAT32 or sub-directory) */ - ic = SS(dp->fs) / SZ_DIRE * dp->fs->csize; /* Entries per cluster */ - while (idx >= ic) { /* Follow cluster chain */ - clst = get_fat(dp->fs, clst); /* Get next cluster */ - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ - if (clst < 2 || clst >= dp->fs->n_fatent) /* Reached to end of table or internal error */ - return FR_INT_ERR; - idx -= ic; - } - sect = clust2sect(dp->fs, clst); - } - dp->clust = clst; /* Current cluster# */ - if (!sect) return FR_INT_ERR; - dp->sect = sect + idx / (SS(dp->fs) / SZ_DIRE); /* Sector# of the directory entry */ - dp->dir = dp->fs->win + (idx % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Ptr to the entry in the sector */ - - return FR_OK; + DWORD clst, sect; + UINT ic; + + dp->index = (WORD)idx; /* Current index */ + clst = dp->sclust; /* Table start cluster (0:root) */ + if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */ + return FR_INT_ERR; + if (!clst && + dp->fs->fs_type == + FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ + clst = dp->fs->dirbase; + + if (clst == 0) { /* Static table (root-directory in FAT12/16) */ + if (idx >= dp->fs->n_rootdir) /* Is index out of range? */ + return FR_INT_ERR; + sect = dp->fs->dirbase; + } else { /* Dynamic table (root-directory in FAT32 or sub-directory) */ + ic = SS(dp->fs) / SZ_DIRE * dp->fs->csize; /* Entries per cluster */ + while (idx >= ic) { /* Follow cluster chain */ + clst = get_fat(dp->fs, clst); /* Get next cluster */ + if (clst == 0xFFFFFFFF) + return FR_DISK_ERR; /* Disk error */ + if (clst < 2 || + clst >= + dp->fs->n_fatent) /* Reached to end of table or internal + error */ + return FR_INT_ERR; + idx -= ic; + } + sect = clust2sect(dp->fs, clst); + } + dp->clust = clst; /* Current cluster# */ + if (!sect) + return FR_INT_ERR; + dp->sect = + sect + + idx / (SS(dp->fs) / SZ_DIRE); /* Sector# of the directory entry */ + dp->dir = dp->fs->win + + (idx % (SS(dp->fs) / SZ_DIRE)) * + SZ_DIRE; /* Ptr to the entry in the sector */ + + return FR_OK; } - - - /*-----------------------------------------------------------------------*/ /* Directory handling - Move directory table index next */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ - DIR* dp, /* Pointer to the directory object */ - int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ -) +static FRESULT +dir_next(/* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not + stretch */ + DIR* dp, /* Pointer to the directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ + ) { - DWORD clst; - UINT i; + DWORD clst; + UINT i; #if !_FS_READONLY - UINT c; -#endif - - - i = dp->index + 1; - if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */ - return FR_NO_FILE; - - if (!(i % (SS(dp->fs) / SZ_DIRE))) { /* Sector changed? */ - dp->sect++; /* Next sector */ - - if (!dp->clust) { /* Static table */ - if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of static table */ - return FR_NO_FILE; - } - else { /* Dynamic table */ - if (((i / (SS(dp->fs) / SZ_DIRE)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */ - clst = get_fat(dp->fs, dp->clust); /* Get next cluster */ - if (clst <= 1) return FR_INT_ERR; - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; - if (clst >= dp->fs->n_fatent) { /* If it reached end of dynamic table, */ + UINT c; +#endif + + i = dp->index + 1; + if (!(i & 0xFFFF) || + !dp->sect) /* Report EOT when index has reached 65535 */ + return FR_NO_FILE; + + if (!(i % (SS(dp->fs) / SZ_DIRE))) { /* Sector changed? */ + dp->sect++; /* Next sector */ + + if (!dp->clust) { /* Static table */ + if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of + static table */ + return FR_NO_FILE; + } else { /* Dynamic table */ + if (((i / (SS(dp->fs) / SZ_DIRE)) & (dp->fs->csize - 1)) == + 0) { /* Cluster changed? */ + clst = get_fat(dp->fs, dp->clust); /* Get next cluster */ + if (clst <= 1) + return FR_INT_ERR; + if (clst == 0xFFFFFFFF) + return FR_DISK_ERR; + if (clst >= + dp->fs + ->n_fatent) { /* If it reached end of dynamic table, */ #if !_FS_READONLY - if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT */ - clst = create_chain(dp->fs, dp->clust); /* Stretch cluster chain */ - if (clst == 0) return FR_DENIED; /* No free cluster */ - if (clst == 1) return FR_INT_ERR; - if (clst == 0xFFFFFFFF) return FR_DISK_ERR; - /* Clean-up stretched table */ - if (sync_window(dp->fs)) return FR_DISK_ERR;/* Flush disk access window */ - mem_set(dp->fs->win, 0, SS(dp->fs)); /* Clear window buffer */ - dp->fs->winsect = clust2sect(dp->fs, clst); /* Cluster start sector */ - for (c = 0; c < dp->fs->csize; c++) { /* Fill the new cluster with 0 */ - dp->fs->wflag = 1; - if (sync_window(dp->fs)) return FR_DISK_ERR; - dp->fs->winsect++; - } - dp->fs->winsect -= c; /* Rewind window offset */ + if (!stretch) + return FR_NO_FILE; /* If do not stretch, report EOT */ + clst = create_chain(dp->fs, + dp->clust); /* Stretch cluster chain */ + if (clst == 0) + return FR_DENIED; /* No free cluster */ + if (clst == 1) + return FR_INT_ERR; + if (clst == 0xFFFFFFFF) + return FR_DISK_ERR; + /* Clean-up stretched table */ + if (sync_window(dp->fs)) + return FR_DISK_ERR; /* Flush disk access window */ + mem_set(dp->fs->win, 0, + SS(dp->fs)); /* Clear window buffer */ + dp->fs->winsect = + clust2sect(dp->fs, clst); /* Cluster start sector */ + for (c = 0; c < dp->fs->csize; + c++) { /* Fill the new cluster with 0 */ + dp->fs->wflag = 1; + if (sync_window(dp->fs)) + return FR_DISK_ERR; + dp->fs->winsect++; + } + dp->fs->winsect -= c; /* Rewind window offset */ #else - if (!stretch) return FR_NO_FILE; /* If do not stretch, report EOT (this is to suppress warning) */ - return FR_NO_FILE; /* Report EOT */ -#endif - } - dp->clust = clst; /* Initialize data for new cluster */ - dp->sect = clust2sect(dp->fs, clst); - } - } - } - - dp->index = (WORD)i; /* Current index */ - dp->dir = dp->fs->win + (i % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Current entry in the window */ - - return FR_OK; + if (!stretch) + return FR_NO_FILE; /* If do not stretch, report EOT + (this is to suppress warning) */ + return FR_NO_FILE; /* Report EOT */ +#endif + } + dp->clust = clst; /* Initialize data for new cluster */ + dp->sect = clust2sect(dp->fs, clst); + } + } + } + + dp->index = (WORD)i; /* Current index */ + dp->dir = dp->fs->win + + (i % (SS(dp->fs) / SZ_DIRE)) * + SZ_DIRE; /* Current entry in the window */ + + return FR_OK; } - - - /*-----------------------------------------------------------------------*/ /* Directory handling - Reserve directory entry */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY -static -FRESULT dir_alloc ( - DIR* dp, /* Pointer to the directory object */ - UINT nent /* Number of contiguous entries to allocate (1-21) */ -) +static FRESULT +dir_alloc(DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate (1-21) */ + ) { - FRESULT res; - UINT n; - - - res = dir_sdi(dp, 0); - if (res == FR_OK) { - n = 0; - do { - res = move_window(dp->fs, dp->sect); - if (res != FR_OK) break; - if (dp->dir[0] == DDEM || dp->dir[0] == 0) { /* Is it a free entry? */ - if (++n == nent) break; /* A block of contiguous free entries is found */ - } else { - n = 0; /* Not a blank entry. Restart to search */ - } - res = dir_next(dp, 1); /* Next entry with table stretch enabled */ - } while (res == FR_OK); - } - if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ - return res; + FRESULT res; + UINT n; + + res = dir_sdi(dp, 0); + if (res == FR_OK) { + n = 0; + do { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) + break; + if (dp->dir[0] == DDEM || + dp->dir[0] == 0) { /* Is it a free entry? */ + if (++n == nent) + break; /* A block of contiguous free entries is found */ + } else { + n = 0; /* Not a blank entry. Restart to search */ + } + res = dir_next(dp, 1); /* Next entry with table stretch enabled */ + } while (res == FR_OK); + } + if (res == FR_NO_FILE) + res = FR_DENIED; /* No directory entry to allocate */ + return res; } #endif - - - /*-----------------------------------------------------------------------*/ /* Directory handling - Load/Store start cluster number */ /*-----------------------------------------------------------------------*/ -static -DWORD ld_clust ( - FATFS* fs, /* Pointer to the fs object */ - BYTE* dir /* Pointer to the directory entry */ -) +static DWORD +ld_clust(FATFS* fs, /* Pointer to the fs object */ + BYTE* dir /* Pointer to the directory entry */ + ) { - DWORD cl; + DWORD cl; - cl = LD_WORD(dir + DIR_FstClusLO); - if (fs->fs_type == FS_FAT32) - cl |= (DWORD)LD_WORD(dir + DIR_FstClusHI) << 16; + cl = LD_WORD(dir + DIR_FstClusLO); + if (fs->fs_type == FS_FAT32) + cl |= (DWORD)LD_WORD(dir + DIR_FstClusHI) << 16; - return cl; + return cl; } - #if !_FS_READONLY -static -void st_clust ( - BYTE* dir, /* Pointer to the directory entry */ - DWORD cl /* Value to be set */ -) +static void +st_clust(BYTE* dir, /* Pointer to the directory entry */ + DWORD cl /* Value to be set */ + ) { - ST_WORD(dir + DIR_FstClusLO, cl); - ST_WORD(dir + DIR_FstClusHI, cl >> 16); + ST_WORD(dir + DIR_FstClusLO, cl); + ST_WORD(dir + DIR_FstClusHI, cl >> 16); } #endif - - - /*-----------------------------------------------------------------------*/ /* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */ /*-----------------------------------------------------------------------*/ #if _USE_LFN -static -const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ - - -static -int cmp_lfn ( /* 1:Matched, 0:Not matched */ - WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ - BYTE* dir /* Pointer to the directory entry containing a part of LFN */ -) +static const BYTE LfnOfs[] = { + 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 +}; /* Offset of LFN characters in the directory entry */ + +static int +cmp_lfn( /* 1:Matched, 0:Not matched */ + WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ + BYTE* dir /* Pointer to the directory entry containing a part of LFN */ + ) { - UINT i, s; - WCHAR wc, uc; - - - i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Get offset in the LFN buffer */ - s = 0; wc = 1; - do { - uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ - if (wc) { /* Last character has not been processed */ - wc = ff_wtoupper(uc); /* Convert it to upper case */ - if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */ - return 0; /* Not matched */ - } else { - if (uc != 0xFFFF) return 0; /* Check filler */ - } - } while (++s < 13); /* Repeat until all characters in the entry are checked */ - - if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */ - return 0; - - return 1; /* The part of LFN matched */ + UINT i, s; + WCHAR wc, uc; + + i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Get offset in the LFN buffer */ + s = 0; + wc = 1; + do { + uc = + LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ + if (wc) { /* Last character has not been processed */ + wc = ff_wtoupper(uc); /* Convert it to upper case */ + if (i >= _MAX_LFN || + wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */ + return 0; /* Not matched */ + } else { + if (uc != 0xFFFF) + return 0; /* Check filler */ + } + } while (++s < + 13); /* Repeat until all characters in the entry are checked */ + + if ((dir[LDIR_Ord] & LLEF) && wc && + lfnbuf[i]) /* Last segment matched but different length */ + return 0; + + return 1; /* The part of LFN matched */ } - - -static -int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ - WCHAR* lfnbuf, /* Pointer to the Unicode-LFN buffer */ - BYTE* dir /* Pointer to the directory entry */ -) +static int +pick_lfn( /* 1:Succeeded, 0:Buffer overflow */ + WCHAR* lfnbuf, /* Pointer to the Unicode-LFN buffer */ + BYTE* dir /* Pointer to the directory entry */ + ) { - UINT i, s; - WCHAR wc, uc; - - - i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ - - s = 0; wc = 1; - do { - uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ - if (wc) { /* Last character has not been processed */ - if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ - lfnbuf[i++] = wc = uc; /* Store it */ - } else { - if (uc != 0xFFFF) return 0; /* Check filler */ - } - } while (++s < 13); /* Read all character in the entry */ - - if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ - if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ - lfnbuf[i] = 0; - } - - return 1; + UINT i, s; + WCHAR wc, uc; + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + s = 0; + wc = 1; + do { + uc = + LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ + if (wc) { /* Last character has not been processed */ + if (i >= _MAX_LFN) + return 0; /* Buffer overflow? */ + lfnbuf[i++] = wc = uc; /* Store it */ + } else { + if (uc != 0xFFFF) + return 0; /* Check filler */ + } + } while (++s < 13); /* Read all character in the entry */ + + if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ + if (i >= _MAX_LFN) + return 0; /* Buffer overflow? */ + lfnbuf[i] = 0; + } + + return 1; } - #if !_FS_READONLY -static -void fit_lfn ( - const WCHAR* lfnbuf, /* Pointer to the LFN buffer */ - BYTE* dir, /* Pointer to the directory entry */ - BYTE ord, /* LFN order (1-20) */ - BYTE sum /* SFN sum */ -) +static void +fit_lfn(const WCHAR* lfnbuf, /* Pointer to the LFN buffer */ + BYTE* dir, /* Pointer to the directory entry */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* SFN sum */ + ) { - UINT i, s; - WCHAR wc; - - - dir[LDIR_Chksum] = sum; /* Set check sum */ - dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ - dir[LDIR_Type] = 0; - ST_WORD(dir + LDIR_FstClusLO, 0); - - i = (ord - 1) * 13; /* Get offset in the LFN buffer */ - s = wc = 0; - do { - if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ - ST_WORD(dir+LfnOfs[s], wc); /* Put it */ - if (!wc) wc = 0xFFFF; /* Padding characters following last character */ - } while (++s < 13); - if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLEF; /* Bottom LFN part is the start of LFN sequence */ - dir[LDIR_Ord] = ord; /* Set the LFN order */ + UINT i, s; + WCHAR wc; + + dir[LDIR_Chksum] = sum; /* Set check sum */ + dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ + dir[LDIR_Type] = 0; + ST_WORD(dir + LDIR_FstClusLO, 0); + + i = (ord - 1) * 13; /* Get offset in the LFN buffer */ + s = wc = 0; + do { + if (wc != 0xFFFF) + wc = lfnbuf[i++]; /* Get an effective character */ + ST_WORD(dir + LfnOfs[s], wc); /* Put it */ + if (!wc) + wc = 0xFFFF; /* Padding characters following last character */ + } while (++s < 13); + if (wc == 0xFFFF || !lfnbuf[i]) + ord |= LLEF; /* Bottom LFN part is the start of LFN sequence */ + dir[LDIR_Ord] = ord; /* Set the LFN order */ } #endif #endif - - - /*-----------------------------------------------------------------------*/ /* Create numbered name */ /*-----------------------------------------------------------------------*/ #if _USE_LFN -static -void gen_numname ( - BYTE* dst, /* Pointer to the buffer to store numbered SFN */ - const BYTE* src, /* Pointer to SFN */ - const WCHAR* lfn, /* Pointer to LFN */ - UINT seq /* Sequence number */ -) +static void +gen_numname(BYTE* dst, /* Pointer to the buffer to store numbered SFN */ + const BYTE* src, /* Pointer to SFN */ + const WCHAR* lfn, /* Pointer to LFN */ + UINT seq /* Sequence number */ + ) { - BYTE ns[8], c; - UINT i, j; - WCHAR wc; - DWORD sr; - - - mem_cpy(dst, src, 11); - - if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */ - sr = seq; - while (*lfn) { /* Create a CRC */ - wc = *lfn++; - for (i = 0; i < 16; i++) { - sr = (sr << 1) + (wc & 1); - wc >>= 1; - if (sr & 0x10000) sr ^= 0x11021; - } - } - seq = (UINT)sr; - } - - /* itoa (hexdecimal) */ - i = 7; - do { - c = (seq % 16) + '0'; - if (c > '9') c += 7; - ns[i--] = c; - seq /= 16; - } while (seq); - ns[i] = '~'; - - /* Append the number */ - for (j = 0; j < i && dst[j] != ' '; j++) { - if (IsDBCS1(dst[j])) { - if (j == i - 1) break; - j++; - } - } - do { - dst[j++] = (i < 8) ? ns[i++] : ' '; - } while (j < 8); + BYTE ns[8], c; + UINT i, j; + WCHAR wc; + DWORD sr; + + mem_cpy(dst, src, 11); + + if (seq > 5) { /* On many collisions, generate a hash number instead of + sequential number */ + sr = seq; + while (*lfn) { /* Create a CRC */ + wc = *lfn++; + for (i = 0; i < 16; i++) { + sr = (sr << 1) + (wc & 1); + wc >>= 1; + if (sr & 0x10000) + sr ^= 0x11021; + } + } + seq = (UINT)sr; + } + + /* itoa (hexdecimal) */ + i = 7; + do { + c = (seq % 16) + '0'; + if (c > '9') + c += 7; + ns[i--] = c; + seq /= 16; + } while (seq); + ns[i] = '~'; + + /* Append the number */ + for (j = 0; j < i && dst[j] != ' '; j++) { + if (IsDBCS1(dst[j])) { + if (j == i - 1) + break; + j++; + } + } + do { + dst[j++] = (i < 8) ? ns[i++] : ' '; + } while (j < 8); } #endif - - - /*-----------------------------------------------------------------------*/ /* Calculate sum of an SFN */ /*-----------------------------------------------------------------------*/ #if _USE_LFN -static -BYTE sum_sfn ( - const BYTE* dir /* Pointer to the SFN entry */ -) +static BYTE +sum_sfn(const BYTE* dir /* Pointer to the SFN entry */ + ) { - BYTE sum = 0; - UINT n = 11; + BYTE sum = 0; + UINT n = 11; - do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); - return sum; + do + sum = (sum >> 1) + (sum << 7) + *dir++; + while (--n); + return sum; } #endif - - - /*-----------------------------------------------------------------------*/ /* Directory handling - Find an object in the directory */ /*-----------------------------------------------------------------------*/ -static -FRESULT dir_find ( - DIR* dp /* Pointer to the directory object linked to the file name */ -) +static FRESULT +dir_find(DIR* dp /* Pointer to the directory object linked to the file name */ + ) { - FRESULT res; - BYTE c, *dir; + FRESULT res; + BYTE c, *dir; #if _USE_LFN - BYTE a, ord, sum; + BYTE a, ord, sum; #endif - res = dir_sdi(dp, 0); /* Rewind directory object */ - if (res != FR_OK) return res; + res = dir_sdi(dp, 0); /* Rewind directory object */ + if (res != FR_OK) + return res; #if _USE_LFN - ord = sum = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ -#endif - do { - res = move_window(dp->fs, dp->sect); - if (res != FR_OK) break; - dir = dp->dir; /* Ptr to the directory entry of current index */ - c = dir[DIR_Name]; - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ -#if _USE_LFN /* LFN configuration */ - a = dir[DIR_Attr] & AM_MASK; - if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ - ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ - } else { - if (a == AM_LFN) { /* An LFN entry is found */ - if (dp->lfn) { - if (c & LLEF) { /* Is it start of LFN sequence? */ - sum = dir[LDIR_Chksum]; - c &= ~LLEF; ord = c; /* LFN start order */ - dp->lfn_idx = dp->index; /* Start index of LFN */ - } - /* Check validity of the LFN entry and compare it with given name */ - ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; - } - } else { /* An SFN entry is found */ - if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */ - if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11)) break; /* SFN matched? */ - ord = 0xFF; dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ - } - } -#else /* Non LFN configuration */ - if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */ - break; -#endif - res = dir_next(dp, 0); /* Next entry */ - } while (res == FR_OK); - - return res; + ord = sum = 0xFF; + dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ +#endif + do { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) + break; + dir = dp->dir; /* Ptr to the directory entry of current index */ + c = dir[DIR_Name]; + if (c == 0) { + res = FR_NO_FILE; + break; + } /* Reached to end of table */ +#if _USE_LFN /* LFN configuration */ + a = dir[DIR_Attr] & AM_MASK; + if (c == DDEM || + ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; + dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (dp->lfn) { + if (c & LLEF) { /* Is it start of LFN sequence? */ + sum = dir[LDIR_Chksum]; + c &= ~LLEF; + ord = c; /* LFN start order */ + dp->lfn_idx = dp->index; /* Start index of LFN */ + } + /* Check validity of the LFN entry and compare it with given + * name */ + ord = (c == ord && sum == dir[LDIR_Chksum] && + cmp_lfn(dp->lfn, dir)) + ? ord - 1 + : 0xFF; + } + } else { /* An SFN entry is found */ + if (!ord && sum == sum_sfn(dir)) + break; /* LFN matched? */ + if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11)) + break; /* SFN matched? */ + ord = 0xFF; + dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + } + } +#else /* Non LFN configuration */ + if (!(dir[DIR_Attr] & AM_VOL) && + !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */ + break; +#endif + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + + return res; } - - - /*-----------------------------------------------------------------------*/ /* Read an object from the directory */ /*-----------------------------------------------------------------------*/ #if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 -static -FRESULT dir_read ( - DIR* dp, /* Pointer to the directory object */ - int vol /* Filtered by 0:file/directory or 1:volume label */ -) +static FRESULT +dir_read(DIR* dp, /* Pointer to the directory object */ + int vol /* Filtered by 0:file/directory or 1:volume label */ + ) { - FRESULT res; - BYTE a, c, *dir; + FRESULT res; + BYTE a, c, *dir; #if _USE_LFN - BYTE ord = 0xFF, sum = 0xFF; -#endif - - res = FR_NO_FILE; - while (dp->sect) { - res = move_window(dp->fs, dp->sect); - if (res != FR_OK) break; - dir = dp->dir; /* Ptr to the directory entry of current index */ - c = dir[DIR_Name]; - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ - a = dir[DIR_Attr] & AM_MASK; -#if _USE_LFN /* LFN configuration */ - if (c == DDEM || (!_FS_RPATH && c == '.') || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ - ord = 0xFF; - } else { - if (a == AM_LFN) { /* An LFN entry is found */ - if (c & LLEF) { /* Is it start of LFN sequence? */ - sum = dir[LDIR_Chksum]; - c &= ~LLEF; ord = c; - dp->lfn_idx = dp->index; - } - /* Check LFN validity and capture it */ - ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF; - } else { /* An SFN entry is found */ - if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */ - dp->lfn_idx = 0xFFFF; /* It has no LFN. */ - break; - } - } -#else /* Non LFN configuration */ - if (c != DDEM && (_FS_RPATH || c != '.') && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) /* Is it a valid entry? */ - break; -#endif - res = dir_next(dp, 0); /* Next entry */ - if (res != FR_OK) break; - } - - if (res != FR_OK) dp->sect = 0; - - return res; + BYTE ord = 0xFF, sum = 0xFF; +#endif + + res = FR_NO_FILE; + while (dp->sect) { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) + break; + dir = dp->dir; /* Ptr to the directory entry of current index */ + c = dir[DIR_Name]; + if (c == 0) { + res = FR_NO_FILE; + break; + } /* Reached to end of table */ + a = dir[DIR_Attr] & AM_MASK; +#if _USE_LFN /* LFN configuration */ + if (c == DDEM || (!_FS_RPATH && c == '.') || + (int)((a & ~AM_ARC) == AM_VOL) != + vol) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (c & LLEF) { /* Is it start of LFN sequence? */ + sum = dir[LDIR_Chksum]; + c &= ~LLEF; + ord = c; + dp->lfn_idx = dp->index; + } + /* Check LFN validity and capture it */ + ord = (c == ord && sum == dir[LDIR_Chksum] && + pick_lfn(dp->lfn, dir)) + ? ord - 1 + : 0xFF; + } else { /* An SFN entry is found */ + if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */ + dp->lfn_idx = 0xFFFF; /* It has no LFN. */ + break; + } + } +#else /* Non LFN configuration */ + if (c != DDEM && (_FS_RPATH || c != '.') && a != AM_LFN && + (int)((a & ~AM_ARC) == AM_VOL) == vol) /* Is it a valid entry? */ + break; +#endif + res = dir_next(dp, 0); /* Next entry */ + if (res != FR_OK) + break; + } + + if (res != FR_OK) + dp->sect = 0; + + return res; } -#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ - - - +#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ /*-----------------------------------------------------------------------*/ /* Register an object to the directory */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY -static -FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */ - DIR* dp /* Target directory with object name to be created */ -) +static FRESULT +dir_register(/* FR_OK:Successful, FR_DENIED:No free entry or too many SFN + collision, FR_DISK_ERR:Disk error */ + DIR* dp /* Target directory with object name to be created */ + ) { - FRESULT res; -#if _USE_LFN /* LFN configuration */ - UINT n, nent; - BYTE sn[12], *fn, sum; - WCHAR *lfn; - - - fn = dp->fn; lfn = dp->lfn; - mem_cpy(sn, fn, 12); - - if (_FS_RPATH && (sn[NSFLAG] & NS_DOT)) /* Cannot create dot entry */ - return FR_INVALID_NAME; - - if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ - fn[NSFLAG] = 0; dp->lfn = 0; /* Find only SFN */ - for (n = 1; n < 100; n++) { - gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ - res = dir_find(dp); /* Check if the name collides with existing SFN */ - if (res != FR_OK) break; - } - if (n == 100) return FR_DENIED; /* Abort if too many collisions */ - if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ - fn[NSFLAG] = sn[NSFLAG]; dp->lfn = lfn; - } - - if (sn[NSFLAG] & NS_LFN) { /* When LFN is to be created, allocate entries for an SFN + LFNs. */ - for (n = 0; lfn[n]; n++) ; - nent = (n + 25) / 13; - } else { /* Otherwise allocate an entry for an SFN */ - nent = 1; - } - res = dir_alloc(dp, nent); /* Allocate entries */ - - if (res == FR_OK && --nent) { /* Set LFN entry if needed */ - res = dir_sdi(dp, dp->index - nent); - if (res == FR_OK) { - sum = sum_sfn(dp->fn); /* Sum value of the SFN tied to the LFN */ - do { /* Store LFN entries in bottom first */ - res = move_window(dp->fs, dp->sect); - if (res != FR_OK) break; - fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum); - dp->fs->wflag = 1; - res = dir_next(dp, 0); /* Next entry */ - } while (res == FR_OK && --nent); - } - } -#else /* Non LFN configuration */ - res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ -#endif - - if (res == FR_OK) { /* Set SFN entry */ - res = move_window(dp->fs, dp->sect); - if (res == FR_OK) { - mem_set(dp->dir, 0, SZ_DIRE); /* Clean the entry */ - mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */ + FRESULT res; +#if _USE_LFN /* LFN configuration */ + UINT n, nent; + BYTE sn[12], *fn, sum; + WCHAR* lfn; + + fn = dp->fn; + lfn = dp->lfn; + mem_cpy(sn, fn, 12); + + if (_FS_RPATH && (sn[NSFLAG] & NS_DOT)) /* Cannot create dot entry */ + return FR_INVALID_NAME; + + if (sn[NSFLAG] & + NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ + fn[NSFLAG] = 0; + dp->lfn = 0; /* Find only SFN */ + for (n = 1; n < 100; n++) { + gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ + res = + dir_find(dp); /* Check if the name collides with existing SFN */ + if (res != FR_OK) + break; + } + if (n == 100) + return FR_DENIED; /* Abort if too many collisions */ + if (res != FR_NO_FILE) + return res; /* Abort if the result is other than 'not collided' */ + fn[NSFLAG] = sn[NSFLAG]; + dp->lfn = lfn; + } + + if (sn[NSFLAG] & NS_LFN) { /* When LFN is to be created, allocate entries + for an SFN + LFNs. */ + for (n = 0; lfn[n]; n++) + ; + nent = (n + 25) / 13; + } else { /* Otherwise allocate an entry for an SFN */ + nent = 1; + } + res = dir_alloc(dp, nent); /* Allocate entries */ + + if (res == FR_OK && --nent) { /* Set LFN entry if needed */ + res = dir_sdi(dp, dp->index - nent); + if (res == FR_OK) { + sum = sum_sfn(dp->fn); /* Sum value of the SFN tied to the LFN */ + do { /* Store LFN entries in bottom first */ + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) + break; + fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum); + dp->fs->wflag = 1; + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK && --nent); + } + } +#else /* Non LFN configuration */ + res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ +#endif + + if (res == FR_OK) { /* Set SFN entry */ + res = move_window(dp->fs, dp->sect); + if (res == FR_OK) { + mem_set(dp->dir, 0, SZ_DIRE); /* Clean the entry */ + mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */ #if _USE_LFN - dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ + dp->dir[DIR_NTres] = + dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ #endif - dp->fs->wflag = 1; - } - } + dp->fs->wflag = 1; + } + } - return res; + return res; } #endif /* !_FS_READONLY */ - - - /*-----------------------------------------------------------------------*/ /* Remove an object from the directory */ /*-----------------------------------------------------------------------*/ #if !_FS_READONLY && !_FS_MINIMIZE -static -FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ - DIR* dp /* Directory object pointing the entry to be removed */ -) +static FRESULT +dir_remove( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ + DIR* dp /* Directory object pointing the entry to be removed */ + ) { - FRESULT res; -#if _USE_LFN /* LFN configuration */ - UINT i; - - i = dp->index; /* SFN index */ - res = dir_sdi(dp, (dp->lfn_idx == 0xFFFF) ? i : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */ - if (res == FR_OK) { - do { - res = move_window(dp->fs, dp->sect); - if (res != FR_OK) break; - mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ - *dp->dir = DDEM; - dp->fs->wflag = 1; - if (dp->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */ - res = dir_next(dp, 0); /* Next entry */ - } while (res == FR_OK); - if (res == FR_NO_FILE) res = FR_INT_ERR; - } - -#else /* Non LFN configuration */ - res = dir_sdi(dp, dp->index); - if (res == FR_OK) { - res = move_window(dp->fs, dp->sect); - if (res == FR_OK) { - mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */ - *dp->dir = DDEM; - dp->fs->wflag = 1; - } - } -#endif - - return res; + FRESULT res; +#if _USE_LFN /* LFN configuration */ + UINT i; + + i = dp->index; /* SFN index */ + res = dir_sdi( + dp, (dp->lfn_idx == 0xFFFF) + ? i + : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */ + if (res == FR_OK) { + do { + res = move_window(dp->fs, dp->sect); + if (res != FR_OK) + break; + mem_set(dp->dir, 0, + SZ_DIRE); /* Clear and mark the entry "deleted" */ + *dp->dir = DDEM; + dp->fs->wflag = 1; + if (dp->index >= i) + break; /* When reached SFN, all entries of the object has been + deleted. */ + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + if (res == FR_NO_FILE) + res = FR_INT_ERR; + } + +#else /* Non LFN configuration */ + res = dir_sdi(dp, dp->index); + if (res == FR_OK) { + res = move_window(dp->fs, dp->sect); + if (res == FR_OK) { + mem_set(dp->dir, 0, + SZ_DIRE); /* Clear and mark the entry "deleted" */ + *dp->dir = DDEM; + dp->fs->wflag = 1; + } + } +#endif + + return res; } #endif /* !_FS_READONLY */ - - - /*-----------------------------------------------------------------------*/ /* Get file information from directory entry */ /*-----------------------------------------------------------------------*/ #if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 -static -void get_fileinfo ( /* No return code */ - DIR* dp, /* Pointer to the directory object */ - FILINFO* fno /* Pointer to the file information to be filled */ -) +static void +get_fileinfo( /* No return code */ + DIR* dp, /* Pointer to the directory object */ + FILINFO* fno /* Pointer to the file information to be filled */ + ) { - UINT i; - TCHAR *p, c; - BYTE *dir; + UINT i; + TCHAR *p, c; + BYTE* dir; #if _USE_LFN - WCHAR w, *lfn; -#endif - - p = fno->fname; - if (dp->sect) { /* Get SFN */ - dir = dp->dir; - i = 0; - while (i < 11) { /* Copy name body and extension */ - c = (TCHAR)dir[i++]; - if (c == ' ') continue; /* Skip padding spaces */ - if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ - if (i == 9) *p++ = '.'; /* Insert a . if extension is exist */ + WCHAR w, *lfn; +#endif + + p = fno->fname; + if (dp->sect) { /* Get SFN */ + dir = dp->dir; + i = 0; + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dir[i++]; + if (c == ' ') + continue; /* Skip padding spaces */ + if (c == RDDEM) + c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) + *p++ = '.'; /* Insert a . if extension is exist */ #if _USE_LFN - if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) - c += 0x20; /* To lower */ + if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) + c += 0x20; /* To lower */ #if _LFN_UNICODE - if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i])) - c = c << 8 | dir[i++]; - c = ff_convert(c, 1); /* OEM -> Unicode */ - if (!c) c = '?'; -#endif -#endif - *p++ = c; - } - fno->fattrib = dir[DIR_Attr]; /* Attribute */ - fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */ - fno->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */ - fno->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */ - } - *p = 0; /* Terminate SFN string by a \0 */ + if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i])) + c = c << 8 | dir[i++]; + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) + c = '?'; +#endif +#endif + *p++ = c; + } + fno->fattrib = dir[DIR_Attr]; /* Attribute */ + fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */ + fno->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */ + fno->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */ + } + *p = 0; /* Terminate SFN string by a \0 */ #if _USE_LFN - if (fno->lfname) { - i = 0; p = fno->lfname; - if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */ - lfn = dp->lfn; - while ((w = *lfn++) != 0) { /* Get an LFN character */ + if (fno->lfname) { + i = 0; + p = fno->lfname; + if (dp->sect && fno->lfsize && + dp->lfn_idx != 0xFFFF) { /* Get LFN if available */ + lfn = dp->lfn; + while ((w = *lfn++) != 0) { /* Get an LFN character */ #if !_LFN_UNICODE - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (!w) { i = 0; break; } /* No LFN if it could not be converted */ - if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */ - p[i++] = (TCHAR)(w >> 8); -#endif - if (i >= fno->lfsize - 1) { i = 0; break; } /* No LFN if buffer overflow */ - p[i++] = (TCHAR)w; - } - } - p[i] = 0; /* Terminate LFN string by a \0 */ - } + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (!w) { + i = 0; + break; + } /* No LFN if it could not be converted */ + if (_DF1S && + w >= + 0x100) /* Put 1st byte if it is a DBC (always false on + SBCS cfg) */ + p[i++] = (TCHAR)(w >> 8); +#endif + if (i >= fno->lfsize - 1) { + i = 0; + break; + } /* No LFN if buffer overflow */ + p[i++] = (TCHAR)w; + } + } + p[i] = 0; /* Terminate LFN string by a \0 */ + } #endif } #endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ - - - /*-----------------------------------------------------------------------*/ /* Pattern matching */ /*-----------------------------------------------------------------------*/ #if _USE_FIND && _FS_MINIMIZE <= 1 -static -WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ - const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ -) +static WCHAR +get_achar(/* Get a character and advances ptr 1 or 2 */ + const TCHAR** + ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ + ) { - WCHAR chr; + WCHAR chr; #if !_LFN_UNICODE - chr = (BYTE)*(*ptr)++; /* Get a byte */ - if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ - if (IsDBCS1(chr) && IsDBCS2(**ptr)) /* Get DBC 2nd byte if needed */ - chr = chr << 8 | (BYTE)*(*ptr)++; + chr = (BYTE) * (*ptr)++; /* Get a byte */ + if (IsLower(chr)) + chr -= 0x20; /* To upper ASCII char */ + if (IsDBCS1(chr) && IsDBCS2(**ptr)) /* Get DBC 2nd byte if needed */ + chr = chr << 8 | (BYTE) * (*ptr)++; #ifdef _EXCVT - if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ + if (chr >= 0x80) + chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ #endif #else - chr = ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ + chr = ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ #endif - return chr; + return chr; } - -static -int pattern_matching ( /* Return value: 0:mismatched, 1:matched */ - const TCHAR* pat, /* Matching pattern */ - const TCHAR* nam, /* String to be tested */ - int skip, /* Number of pre-skip chars (number of ?s) */ - int inf /* Infinite search (* specified) */ -) +static int +pattern_matching( /* Return value: 0:mismatched, 1:matched */ + const TCHAR* pat, /* Matching pattern */ + const TCHAR* nam, /* String to be tested */ + int skip, /* Number of pre-skip chars (number of ?s) */ + int inf /* Infinite search (* specified) */ + ) { - const TCHAR *pp, *np; - WCHAR pc, nc; - int nm, nx; - - - while (skip--) { /* Pre-skip name chars */ - if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ - } - if (!*pat && inf) return 1; /* (short circuit) */ - - do { - pp = pat; np = nam; /* Top of pattern and name to match */ - for (;;) { - if (*pp == '?' || *pp == '*') { /* Wildcard? */ - nm = nx = 0; - do { /* Analyze the wildcard chars */ - if (*pp++ == '?') nm++; else nx = 1; - } while (*pp == '?' || *pp == '*'); - if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ - nc = *np; break; /* Branch mismatched */ - } - pc = get_achar(&pp); /* Get a pattern char */ - nc = get_achar(&np); /* Get a name char */ - if (pc != nc) break; /* Branch mismatched? */ - if (!pc) return 1; /* Branch matched? (matched at end of both strings) */ - } - get_achar(&nam); /* nam++ */ - } while (inf && nc); /* Retry until end of name if infinite search is specified */ - - return 0; + const TCHAR *pp, *np; + WCHAR pc, nc; + int nm, nx; + + while (skip--) { /* Pre-skip name chars */ + if (!get_achar(&nam)) + return 0; /* Branch mismatched if less name chars */ + } + if (!*pat && inf) + return 1; /* (short circuit) */ + + do { + pp = pat; + np = nam; /* Top of pattern and name to match */ + for (;;) { + if (*pp == '?' || *pp == '*') { /* Wildcard? */ + nm = nx = 0; + do { /* Analyze the wildcard chars */ + if (*pp++ == '?') + nm++; + else + nx = 1; + } while (*pp == '?' || *pp == '*'); + if (pattern_matching(pp, np, nm, nx)) + return 1; /* Test new branch (recurs upto number of wildcard + blocks in the pattern) */ + nc = *np; + break; /* Branch mismatched */ + } + pc = get_achar(&pp); /* Get a pattern char */ + nc = get_achar(&np); /* Get a name char */ + if (pc != nc) + break; /* Branch mismatched? */ + if (!pc) + return 1; /* Branch matched? (matched at end of both strings) */ + } + get_achar(&nam); /* nam++ */ + } while (inf && + nc); /* Retry until end of name if infinite search is specified */ + + return 0; } #endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ - - - /*-----------------------------------------------------------------------*/ /* Pick a segment and create the object name in directory form */ /*-----------------------------------------------------------------------*/ -static -FRESULT create_name ( - DIR* dp, /* Pointer to the directory object */ - const TCHAR** path /* Pointer to pointer to the segment in the path string */ -) +static FRESULT +create_name(DIR* dp, /* Pointer to the directory object */ + const TCHAR** + path /* Pointer to pointer to the segment in the path string */ + ) { -#if _USE_LFN /* LFN configuration */ - BYTE b, cf; - WCHAR w, *lfn; - UINT i, ni, si, di; - const TCHAR *p; - - /* Create LFN in Unicode */ - for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ - lfn = dp->lfn; - si = di = 0; - for (;;) { - w = p[si++]; /* Get a character */ - if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */ - if (di >= _MAX_LFN) /* Reject too long name */ - return FR_INVALID_NAME; +#if _USE_LFN /* LFN configuration */ + BYTE b, cf; + WCHAR w, *lfn; + UINT i, ni, si, di; + const TCHAR* p; + + /* Create LFN in Unicode */ + for (p = *path; *p == '/' || *p == '\\'; p++) + ; /* Strip duplicated separator */ + lfn = dp->lfn; + si = di = 0; + for (;;) { + w = p[si++]; /* Get a character */ + if (w < ' ' || w == '/' || w == '\\') + break; /* Break on end of segment */ + if (di >= _MAX_LFN) /* Reject too long name */ + return FR_INVALID_NAME; #if !_LFN_UNICODE - w &= 0xFF; - if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ - b = (BYTE)p[si++]; /* Get 2nd byte */ - w = (w << 8) + b; /* Create a DBC */ - if (!IsDBCS2(b)) - return FR_INVALID_NAME; /* Reject invalid sequence */ - } - w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ - if (!w) return FR_INVALID_NAME; /* Reject invalid code */ -#endif - if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */ - return FR_INVALID_NAME; - lfn[di++] = w; /* Store the Unicode character */ - } - *path = &p[si]; /* Return pointer to the next segment */ - cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ + w &= 0xFF; + if (IsDBCS1( + w)) { /* Check if it is a DBC 1st byte (always false on SBCS + cfg) */ + b = (BYTE)p[si++]; /* Get 2nd byte */ + w = (w << 8) + b; /* Create a DBC */ + if (!IsDBCS2(b)) + return FR_INVALID_NAME; /* Reject invalid sequence */ + } + w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ + if (!w) + return FR_INVALID_NAME; /* Reject invalid code */ +#endif + if (w < 0x80 && + chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */ + return FR_INVALID_NAME; + lfn[di++] = w; /* Store the Unicode character */ + } + *path = &p[si]; /* Return pointer to the next segment */ + cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ #if _FS_RPATH - if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */ - (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { - lfn[di] = 0; - for (i = 0; i < 11; i++) - dp->fn[i] = (i < di) ? '.' : ' '; - dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ - return FR_OK; - } -#endif - while (di) { /* Strip trailing spaces and dots */ - w = lfn[di - 1]; - if (w != ' ' && w != '.') break; - di--; - } - if (!di) return FR_INVALID_NAME; /* Reject nul string */ - - lfn[di] = 0; /* LFN is created */ - - /* Create SFN in directory form */ - mem_set(dp->fn, ' ', 11); - for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */ - if (si) cf |= NS_LOSS | NS_LFN; - while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ - - b = i = 0; ni = 8; - for (;;) { - w = lfn[si++]; /* Get an LFN character */ - if (!w) break; /* Break on end of the LFN */ - if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ - cf |= NS_LOSS | NS_LFN; continue; - } - - if (i >= ni || si == di) { /* Extension or end of SFN */ - if (ni == 11) { /* Long extension */ - cf |= NS_LOSS | NS_LFN; break; - } - if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ - if (si > di) break; /* No extension */ - si = di; i = 8; ni = 11; /* Enter extension section */ - b <<= 2; continue; - } - - if (w >= 0x80) { /* Non ASCII character */ + if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */ + (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { + lfn[di] = 0; + for (i = 0; i < 11; i++) + dp->fn[i] = (i < di) ? '.' : ' '; + dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ + return FR_OK; + } +#endif + while (di) { /* Strip trailing spaces and dots */ + w = lfn[di - 1]; + if (w != ' ' && w != '.') + break; + di--; + } + if (!di) + return FR_INVALID_NAME; /* Reject nul string */ + + lfn[di] = 0; /* LFN is created */ + + /* Create SFN in directory form */ + mem_set(dp->fn, ' ', 11); + for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) + ; /* Strip leading spaces and dots */ + if (si) + cf |= NS_LOSS | NS_LFN; + while (di && lfn[di - 1] != '.') + di--; /* Find extension (di<=si: no extension) */ + + b = i = 0; + ni = 8; + for (;;) { + w = lfn[si++]; /* Get an LFN character */ + if (!w) + break; /* Break on end of the LFN */ + if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ + cf |= NS_LOSS | NS_LFN; + continue; + } + + if (i >= ni || si == di) { /* Extension or end of SFN */ + if (ni == 11) { /* Long extension */ + cf |= NS_LOSS | NS_LFN; + break; + } + if (si != di) + cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ + if (si > di) + break; /* No extension */ + si = di; + i = 8; + ni = 11; /* Enter extension section */ + b <<= 2; + continue; + } + + if (w >= 0x80) { /* Non ASCII character */ #ifdef _EXCVT - w = ff_convert(w, 0); /* Unicode -> OEM code */ - if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */ + w = ff_convert(w, 0); /* Unicode -> OEM code */ + if (w) + w = ExCvt[w - 0x80]; /* Convert extended character to upper + (SBCS) */ #else - w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */ -#endif - cf |= NS_LFN; /* Force create LFN entry */ - } - - if (_DF1S && w >= 0x100) { /* DBC (always false at SBCS cfg) */ - if (i >= ni - 1) { - cf |= NS_LOSS | NS_LFN; i = ni; continue; - } - dp->fn[i++] = (BYTE)(w >> 8); - } else { /* SBC */ - if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */ - w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ - } else { - if (IsUpper(w)) { /* ASCII large capital */ - b |= 2; - } else { - if (IsLower(w)) { /* ASCII small capital */ - b |= 1; w -= 0x20; - } - } - } - } - dp->fn[i++] = (BYTE)w; - } - - if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with deleted mark, replace it with RDDEM */ - - if (ni == 8) b <<= 2; - if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ - cf |= NS_LFN; - if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ - if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ - if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ - } - - dp->fn[NSFLAG] = cf; /* SFN is created */ - - return FR_OK; - - -#else /* Non-LFN configuration */ - BYTE b, c, d, *sfn; - UINT ni, si, i; - const char *p; - - /* Create file name in directory form */ - for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ - sfn = dp->fn; - mem_set(sfn, ' ', 11); - si = i = b = 0; ni = 8; + w = ff_convert(ff_wtoupper(w), + 0); /* Upper converted Unicode -> OEM code */ +#endif + cf |= NS_LFN; /* Force create LFN entry */ + } + + if (_DF1S && w >= 0x100) { /* DBC (always false at SBCS cfg) */ + if (i >= ni - 1) { + cf |= NS_LOSS | NS_LFN; + i = ni; + continue; + } + dp->fn[i++] = (BYTE)(w >> 8); + } else { /* SBC */ + if (!w || + chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */ + w = '_'; + cf |= NS_LOSS | NS_LFN; /* Lossy conversion */ + } else { + if (IsUpper(w)) { /* ASCII large capital */ + b |= 2; + } else { + if (IsLower(w)) { /* ASCII small capital */ + b |= 1; + w -= 0x20; + } + } + } + } + dp->fn[i++] = (BYTE)w; + } + + if (dp->fn[0] == DDEM) + dp + ->fn[0] = RDDEM; /* If the first character collides with deleted + mark, replace it with RDDEM */ + + if (ni == 8) + b <<= 2; + if ((b & 0x0C) == 0x0C || + (b & 0x03) == + 0x03) /* Create LFN entry when there are composite capitals */ + cf |= NS_LFN; + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended + character, NT flags are created */ + if ((b & 0x03) == 0x01) + cf |= NS_EXT; /* NT flag (Extension has only small capital) */ + if ((b & 0x0C) == 0x04) + cf |= NS_BODY; /* NT flag (Filename has only small capital) */ + } + + dp->fn[NSFLAG] = cf; /* SFN is created */ + + return FR_OK; + +#else /* Non-LFN configuration */ + BYTE b, c, d, *sfn; + UINT ni, si, i; + const char* p; + + /* Create file name in directory form */ + for (p = *path; *p == '/' || *p == '\\'; p++) + ; /* Strip duplicated separator */ + sfn = dp->fn; + mem_set(sfn, ' ', 11); + si = i = b = 0; + ni = 8; #if _FS_RPATH - if (p[si] == '.') { /* Is this a dot entry? */ - for (;;) { - c = (BYTE)p[si++]; - if (c != '.' || si >= 3) break; - sfn[i++] = c; - } - if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; - *path = &p[si]; /* Return pointer to the next segment */ - sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */ - return FR_OK; - } -#endif - for (;;) { - c = (BYTE)p[si++]; - if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */ - if (c == '.' || i >= ni) { - if (ni != 8 || c != '.') return FR_INVALID_NAME; - i = 8; ni = 11; - b <<= 2; continue; - } - if (c >= 0x80) { /* Extended character? */ - b |= 3; /* Eliminate NT flag */ + if (p[si] == '.') { /* Is this a dot entry? */ + for (;;) { + c = (BYTE)p[si++]; + if (c != '.' || si >= 3) + break; + sfn[i++] = c; + } + if (c != '/' && c != '\\' && c > ' ') + return FR_INVALID_NAME; + *path = &p[si]; /* Return pointer to the next segment */ + sfn[NSFLAG] = (c <= ' ') + ? NS_LAST | NS_DOT + : NS_DOT; /* Set last segment flag if end of path */ + return FR_OK; + } +#endif + for (;;) { + c = (BYTE)p[si++]; + if (c <= ' ' || c == '/' || c == '\\') + break; /* Break on end of segment */ + if (c == '.' || i >= ni) { + if (ni != 8 || c != '.') + return FR_INVALID_NAME; + i = 8; + ni = 11; + b <<= 2; + continue; + } + if (c >= 0x80) { /* Extended character? */ + b |= 3; /* Eliminate NT flag */ #ifdef _EXCVT - c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ + c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ #else #if !_DF1S - return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */ -#endif -#endif - } - if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ - d = (BYTE)p[si++]; /* Get 2nd byte */ - if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ - return FR_INVALID_NAME; - sfn[i++] = c; - sfn[i++] = d; - } else { /* SBC */ - if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */ - return FR_INVALID_NAME; - if (IsUpper(c)) { /* ASCII large capital? */ - b |= 2; - } else { - if (IsLower(c)) { /* ASCII small capital? */ - b |= 1; c -= 0x20; - } - } - sfn[i++] = c; - } - } - *path = &p[si]; /* Return pointer to the next segment */ - c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ - - if (!i) return FR_INVALID_NAME; /* Reject nul string */ - if (sfn[0] == DDEM) sfn[0] = RDDEM; /* When first character collides with DDEM, replace it with RDDEM */ - - if (ni == 8) b <<= 2; - if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */ - if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */ - - sfn[NSFLAG] = c; /* Store NT flag, File name is created */ - - return FR_OK; + return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */ +#endif +#endif + } + if (IsDBCS1( + c)) { /* Check if it is a DBC 1st byte (always false on SBCS + cfg) */ + d = (BYTE)p[si++]; /* Get 2nd byte */ + if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ + return FR_INVALID_NAME; + sfn[i++] = c; + sfn[i++] = d; + } else { /* SBC */ + if (chk_chr("\"*+,:;<=>\?[]|\x7F", + c)) /* Reject illegal chrs for SFN */ + return FR_INVALID_NAME; + if (IsUpper(c)) { /* ASCII large capital? */ + b |= 2; + } else { + if (IsLower(c)) { /* ASCII small capital? */ + b |= 1; + c -= 0x20; + } + } + sfn[i++] = c; + } + } + *path = &p[si]; /* Return pointer to the next segment */ + c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ + + if (!i) + return FR_INVALID_NAME; /* Reject nul string */ + if (sfn[0] == DDEM) + sfn[0] = RDDEM; /* When first character collides with DDEM, replace it + with RDDEM */ + + if (ni == 8) + b <<= 2; + if ((b & 0x03) == 0x01) + c |= NS_EXT; /* NT flag (Name extension has only small capital) */ + if ((b & 0x0C) == 0x04) + c |= NS_BODY; /* NT flag (Name body has only small capital) */ + + sfn[NSFLAG] = c; /* Store NT flag, File name is created */ + + return FR_OK; #endif } - - - /*-----------------------------------------------------------------------*/ /* Follow a file path */ /*-----------------------------------------------------------------------*/ -static -FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ - DIR* dp, /* Directory object to return last directory and found object */ - const TCHAR* path /* Full-path string to find a file or directory */ -) +static FRESULT +follow_path( /* FR_OK(0): successful, !=0: error code */ + DIR* dp, /* Directory object to return last directory and found + object */ + const TCHAR* path /* Full-path string to find a file or directory */ + ) { - FRESULT res; - BYTE *dir, ns; - + FRESULT res; + BYTE *dir, ns; #if _FS_RPATH - if (*path == '/' || *path == '\\') { /* There is a heading separator */ - path++; dp->sclust = 0; /* Strip it and start from the root directory */ - } else { /* No heading separator */ - dp->sclust = dp->fs->cdir; /* Start from the current directory */ - } + if (*path == '/' || *path == '\\') { /* There is a heading separator */ + path++; + dp->sclust = 0; /* Strip it and start from the root directory */ + } else { /* No heading separator */ + dp->sclust = dp->fs->cdir; /* Start from the current directory */ + } #else - if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ - path++; - dp->sclust = 0; /* Always start from the root directory */ -#endif - - if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ - res = dir_sdi(dp, 0); - dp->dir = 0; - } else { /* Follow path */ - for (;;) { - res = create_name(dp, &path); /* Get a segment name of the path */ - if (res != FR_OK) break; - res = dir_find(dp); /* Find an object with the sagment name */ - ns = dp->fn[NSFLAG]; - if (res != FR_OK) { /* Failed to find the object */ - if (res == FR_NO_FILE) { /* Object is not found */ - if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, */ - dp->sclust = 0; dp->dir = 0; /* it is the root directory and stay there */ - if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ - res = FR_OK; /* Ended at the root directroy. Function completed. */ - } else { /* Could not find the object */ - if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ - } - } - break; - } - if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ - dir = dp->dir; /* Follow the sub-directory */ - if (!(dir[DIR_Attr] & AM_DIR)) { /* It is not a sub-directory and cannot follow */ - res = FR_NO_PATH; break; - } - dp->sclust = ld_clust(dp->fs, dir); - } - } - - return res; + if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ + path++; + dp->sclust = 0; /* Always start from the root directory */ +#endif + + if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ + res = dir_sdi(dp, 0); + dp->dir = 0; + } else { /* Follow path */ + for (;;) { + res = create_name(dp, &path); /* Get a segment name of the path */ + if (res != FR_OK) + break; + res = dir_find(dp); /* Find an object with the sagment name */ + ns = dp->fn[NSFLAG]; + if (res != FR_OK) { /* Failed to find the object */ + if (res == FR_NO_FILE) { /* Object is not found */ + if (_FS_RPATH && + (ns & NS_DOT)) { /* If dot entry is not exist, */ + dp->sclust = 0; + dp->dir = + 0; /* it is the root directory and stay there */ + if (!(ns & NS_LAST)) + continue; /* Continue to follow if not last segment + */ + res = FR_OK; /* Ended at the root directroy. Function + completed. */ + } else { /* Could not find the object */ + if (!(ns & NS_LAST)) + res = FR_NO_PATH; /* Adjust error code if not last + segment */ + } + } + break; + } + if (ns & NS_LAST) + break; /* Last segment matched. Function completed. */ + dir = dp->dir; /* Follow the sub-directory */ + if (!(dir[DIR_Attr] & + AM_DIR)) { /* It is not a sub-directory and cannot follow */ + res = FR_NO_PATH; + break; + } + dp->sclust = ld_clust(dp->fs, dir); + } + } + + return res; } - - - /*-----------------------------------------------------------------------*/ /* Get logical drive number from path name */ /*-----------------------------------------------------------------------*/ -static -int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ - const TCHAR** path /* Pointer to pointer to the path name */ -) +static int +get_ldnumber(/* Returns logical drive number (-1:invalid drive) */ + const TCHAR** path /* Pointer to pointer to the path name */ + ) { - const TCHAR *tp, *tt; - UINT i; - int vol = -1; -#if _STR_VOLUME_ID /* Find string drive id */ - static const char* const str[] = {_VOLUME_STRS}; - const char *sp; - char c; - TCHAR tc; -#endif - - - if (*path) { /* If the pointer is not a null */ - for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */ - if (*tt == ':') { /* If a ':' is exist in the path name */ - tp = *path; - i = *tp++ - '0'; - if (i < 10 && tp == tt) { /* Is there a numeric drive id? */ - if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ - vol = (int)i; - *path = ++tt; - } - } + const TCHAR *tp, *tt; + UINT i; + int vol = -1; +#if _STR_VOLUME_ID /* Find string drive id */ + static const char* const str[] = { _VOLUME_STRS }; + const char* sp; + char c; + TCHAR tc; +#endif + + if (*path) { /* If the pointer is not a null */ + for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; + tt++) + ; /* Find ':' in the path */ + if (*tt == ':') { /* If a ':' is exist in the path name */ + tp = *path; + i = *tp++ - '0'; + if (i < 10 && tp == tt) { /* Is there a numeric drive id? */ + if (i < + _VOLUMES) { /* If a drive id is found, get the value and + strip it */ + vol = (int)i; + *path = ++tt; + } + } #if _STR_VOLUME_ID - else { /* No numeric drive number, find string drive id */ - i = 0; tt++; - do { - sp = str[i]; tp = *path; - do { /* Compare a string drive id with path name */ - c = *sp++; tc = *tp++; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || tp != tt) && ++i < _VOLUMES); /* Repeat for each id until pattern match */ - if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ - vol = (int)i; - *path = tt; - } - } -#endif - return vol; - } + else { /* No numeric drive number, find string drive id */ + i = 0; + tt++; + do { + sp = str[i]; + tp = *path; + do { /* Compare a string drive id with path name */ + c = *sp++; + tc = *tp++; + if (IsLower(tc)) + tc -= 0x20; + } while (c && (TCHAR)c == tc); + } while ( + (c || tp != tt) && + ++i < + _VOLUMES); /* Repeat for each id until pattern match */ + if (i < + _VOLUMES) { /* If a drive id is found, get the value and + strip it */ + vol = (int)i; + *path = tt; + } + } +#endif + return vol; + } #if _FS_RPATH && _VOLUMES >= 2 - vol = CurrVol; /* Current drive */ + vol = CurrVol; /* Current drive */ #else - vol = 0; /* Drive 0 */ + vol = 0; /* Drive 0 */ #endif - } - return vol; + } + return vol; } - - - /*-----------------------------------------------------------------------*/ /* Load a sector and check if it is an FAT boot sector */ /*-----------------------------------------------------------------------*/ -static -BYTE check_fs ( /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot sector, 3:Disk error */ - FATFS* fs, /* File system object */ - DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ -) +static BYTE +check_fs(/* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot + sector, 3:Disk error */ + FATFS* fs, /* File system object */ + DWORD + sect /* Sector# (lba) to check if it is an FAT boot record or not + */ + ) { - fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ - if (move_window(fs, sect) != FR_OK) /* Load boot record */ - return 3; - - if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ - return 2; - - if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ - return 0; - if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ - return 0; - - return 1; + fs->wflag = 0; + fs->winsect = 0xFFFFFFFF; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) /* Load boot record */ + return 3; + + if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature + (always placed at offset 510 + even if the sector size is + >512) */ + return 2; + + if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == + 0x544146) /* Check "FAT" string */ + return 0; + if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == + 0x544146) /* Check "FAT" string */ + return 0; + + return 1; } - - - /*-----------------------------------------------------------------------*/ /* Find logical drive and check if the volume is mounted */ /*-----------------------------------------------------------------------*/ -static -FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ - FATFS** rfs, /* Pointer to pointer to the found file system object */ - const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ - BYTE wmode /* !=0: Check write protection for write access */ -) +static FRESULT +find_volume(/* FR_OK(0): successful, !=0: any error occurred */ + FATFS** + rfs, /* Pointer to pointer to the found file system object */ + const TCHAR** + path, /* Pointer to pointer to the path name (drive number) */ + BYTE wmode /* !=0: Check write protection for write access */ + ) { - BYTE fmt, *pt; - int vol; - DSTATUS stat; - DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; - WORD nrsv; - FATFS *fs; - UINT i; - - - /* Get logical drive number from the path name */ - *rfs = 0; - vol = get_ldnumber(path); - if (vol < 0) return FR_INVALID_DRIVE; - - /* Check if the file system object is valid or not */ - fs = FatFs[vol]; /* Get pointer to the file system object */ - if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ - - ENTER_FF(fs); /* Lock the volume */ - *rfs = fs; /* Return pointer to the file system object */ - - if (fs->fs_type) { /* If the volume has been mounted */ - stat = disk_status(fs->drv); - if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ - if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */ - return FR_WRITE_PROTECTED; - return FR_OK; /* The file system object is valid */ - } - } - - /* The file system object is not valid. */ - /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */ - - fs->fs_type = 0; /* Clear the file system object */ - fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */ - stat = disk_initialize(fs->drv); /* Initialize the physical drive */ - if (stat & STA_NOINIT) /* Check if the initialization succeeded */ - return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ - if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */ - return FR_WRITE_PROTECTED; -#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ - if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK - || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) return FR_DISK_ERR; -#endif - /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ - bsect = 0; - fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ - if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */ - for (i = 0; i < 4; i++) { /* Get partition offset */ - pt = fs->win + MBR_Table + i * SZ_PTE; - br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0; - } - i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ - if (i) i--; - do { /* Find an FAT volume */ - bsect = br[i]; - fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */ - } while (!LD2PT(vol) && fmt && ++i < 4); - } - if (fmt == 3) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ - if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - - /* An FAT volume is found. Following code initializes the file system object */ - - if (LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ - return FR_NO_FILESYSTEM; - - fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ - if (!fasize) fasize = LD_DWORD(fs->win + BPB_FATSz32); - fs->fsize = fasize; - - fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ - if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */ - return FR_NO_FILESYSTEM; - fasize *= fs->n_fats; /* Number of sectors for FAT area */ - - fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ - if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */ - return FR_NO_FILESYSTEM; - - fs->n_rootdir = LD_WORD(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ - if (fs->n_rootdir % (SS(fs) / SZ_DIRE)) /* (Must be sector aligned) */ - return FR_NO_FILESYSTEM; - - tsect = LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ - if (!tsect) tsect = LD_DWORD(fs->win + BPB_TotSec32); - - nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ - if (!nrsv) return FR_NO_FILESYSTEM; /* (Must not be 0) */ - - /* Determine the FAT sub type */ - sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + DIR */ - if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ - if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - fmt = FS_FAT12; - if (nclst >= MIN_FAT16) fmt = FS_FAT16; - if (nclst >= MIN_FAT32) fmt = FS_FAT32; - - /* Boundaries and Limits */ - fs->n_fatent = nclst + 2; /* Number of FAT entries */ - fs->volbase = bsect; /* Volume start sector */ - fs->fatbase = bsect + nrsv; /* FAT start sector */ - fs->database = bsect + sysect; /* Data start sector */ - if (fmt == FS_FAT32) { - if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ - fs->dirbase = LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */ - szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ - } else { - if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ - fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ - szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ - fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); - } - if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than the size needed) */ - return FR_NO_FILESYSTEM; + BYTE fmt, *pt; + int vol; + DSTATUS stat; + DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; + WORD nrsv; + FATFS* fs; + UINT i; + + /* Get logical drive number from the path name */ + *rfs = 0; + vol = get_ldnumber(path); + if (vol < 0) + return FR_INVALID_DRIVE; + + /* Check if the file system object is valid or not */ + fs = FatFs[vol]; /* Get pointer to the file system object */ + if (!fs) + return FR_NOT_ENABLED; /* Is the file system object available? */ + + ENTER_FF(fs); /* Lock the volume */ + *rfs = fs; /* Return pointer to the file system object */ + + if (fs->fs_type) { /* If the volume has been mounted */ + stat = disk_status(fs->drv); + if (!(stat & + STA_NOINIT)) { /* and the physical drive is kept initialized */ + if (!_FS_READONLY && wmode && + (stat & STA_PROTECT)) /* Check write protection if needed */ + return FR_WRITE_PROTECTED; + return FR_OK; /* The file system object is valid */ + } + } + + /* The file system object is not valid. */ + /* Following code attempts to mount the volume. (analyze BPB and initialize + * the fs object) */ + + fs->fs_type = 0; /* Clear the file system object */ + fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */ + stat = disk_initialize(fs->drv); /* Initialize the physical drive */ + if (stat & STA_NOINIT) /* Check if the initialization succeeded */ + return FR_NOT_READY; /* Failed to initialize due to no medium or hard + error */ + if (!_FS_READONLY && wmode && + (stat & STA_PROTECT)) /* Check disk write protection if needed */ + return FR_WRITE_PROTECTED; +#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ + if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || + SS(fs) < _MIN_SS || SS(fs) > _MAX_SS) + return FR_DISK_ERR; +#endif + /* Find an FAT partition on the drive. Supports only generic partitioning, + * FDISK and SFD. */ + bsect = 0; + fmt = check_fs( + fs, + bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */ + if (fmt == 1 || + (!fmt && + (LD2PT( + vol)))) { /* Not an FAT boot sector or forced partition number */ + for (i = 0; i < 4; i++) { /* Get partition offset */ + pt = fs->win + MBR_Table + i * SZ_PTE; + br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0; + } + i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ + if (i) + i--; + do { /* Find an FAT volume */ + bsect = br[i]; + fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */ + } while (!LD2PT(vol) && fmt && ++i < 4); + } + if (fmt == 3) + return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt) + return FR_NO_FILESYSTEM; /* No FAT volume is found */ + + /* An FAT volume is found. Following code initializes the file system object + */ + + if (LD_WORD(fs->win + BPB_BytsPerSec) != + SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; + + fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (!fasize) + fasize = LD_DWORD(fs->win + BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */ + if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */ + return FR_NO_FILESYSTEM; + fasize *= fs->n_fats; /* Number of sectors for FAT area */ + + fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ + if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */ + return FR_NO_FILESYSTEM; + + fs->n_rootdir = LD_WORD( + fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / SZ_DIRE)) /* (Must be sector aligned) */ + return FR_NO_FILESYSTEM; + + tsect = + LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (!tsect) + tsect = LD_DWORD(fs->win + BPB_TotSec32); + + nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (!nrsv) + return FR_NO_FILESYSTEM; /* (Must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + DIR */ + if (tsect < sysect) + return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (!nclst) + return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = FS_FAT12; + if (nclst >= MIN_FAT16) + fmt = FS_FAT16; + if (nclst >= MIN_FAT32) + fmt = FS_FAT32; + + /* Boundaries and Limits */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ + if (fmt == FS_FAT32) { + if (fs->n_rootdir) + return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = + LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + } else { + if (!fs->n_rootdir) + return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->n_fatent * 2 + : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < + (szbfat + (SS(fs) - 1)) / + SS(fs)) /* (BPB_FATSz must not be less than the size needed) */ + return FR_NO_FILESYSTEM; #if !_FS_READONLY - /* Initialize cluster allocation information */ - fs->last_clust = fs->free_clust = 0xFFFFFFFF; + /* Initialize cluster allocation information */ + fs->last_clust = fs->free_clust = 0xFFFFFFFF; - /* Get fsinfo if available */ - fs->fsi_flag = 0x80; + /* Get fsinfo if available */ + fs->fsi_flag = 0x80; #if (_FS_NOFSINFO & 3) != 3 - if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */ - && LD_WORD(fs->win + BPB_FSInfo) == 1 - && move_window(fs, bsect + 1) == FR_OK) - { - fs->fsi_flag = 0; - if (LD_WORD(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ - && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252 - && LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272) - { + if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */ + && LD_WORD(fs->win + BPB_FSInfo) == 1 && + move_window(fs, bsect + 1) == FR_OK) { + fs->fsi_flag = 0; + if (LD_WORD(fs->win + BS_55AA) == + 0xAA55 /* Load FSINFO data if available */ + && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252 && + LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272) { #if (_FS_NOFSINFO & 1) == 0 - fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count); + fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count); #endif #if (_FS_NOFSINFO & 2) == 0 - fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free); + fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free); #endif - } - } + } + } #endif #endif - fs->fs_type = fmt; /* FAT sub-type */ - fs->id = ++Fsid; /* File system mount ID */ + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* File system mount ID */ #if _FS_RPATH - fs->cdir = 0; /* Set current directory to root */ + fs->cdir = 0; /* Set current directory to root */ #endif -#if _FS_LOCK /* Clear file lock semaphores */ - clear_lock(fs); +#if _FS_LOCK /* Clear file lock semaphores */ + clear_lock(fs); #endif - return FR_OK; + return FR_OK; } - - - /*-----------------------------------------------------------------------*/ /* Check if the file/directory object is valid or not */ /*-----------------------------------------------------------------------*/ -static -FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ - void* obj /* Pointer to the object FIL/DIR to check validity */ -) +static FRESULT +validate( /* FR_OK(0): The object is valid, !=0: Invalid */ + void* obj /* Pointer to the object FIL/DIR to check validity */ + ) { - FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */ - + FIL* fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR + structure is identical */ - if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id) - return FR_INVALID_OBJECT; + if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id) + return FR_INVALID_OBJECT; - ENTER_FF(fil->fs); /* Lock file system */ + ENTER_FF(fil->fs); /* Lock file system */ - if (disk_status(fil->fs->drv) & STA_NOINIT) - return FR_NOT_READY; + if (disk_status(fil->fs->drv) & STA_NOINIT) + return FR_NOT_READY; - return FR_OK; + return FR_OK; } - - - /*-------------------------------------------------------------------------- Public Functions --------------------------------------------------------------------------*/ - - /*-----------------------------------------------------------------------*/ /* Mount/Unmount a Logical Drive */ /*-----------------------------------------------------------------------*/ -FRESULT f_mount ( - FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/ - const TCHAR* path, /* Logical drive number to be mounted/unmounted */ - BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */ -) +FRESULT +f_mount(FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/ + const TCHAR* path, /* Logical drive number to be mounted/unmounted */ + BYTE opt /* 0:Do not mount (delayed mount), 1:Mount immediately */ + ) { - FATFS *cfs; - int vol; - FRESULT res; - const TCHAR *rp = path; - + FATFS* cfs; + int vol; + FRESULT res; + const TCHAR* rp = path; - vol = get_ldnumber(&rp); - if (vol < 0) return FR_INVALID_DRIVE; - cfs = FatFs[vol]; /* Pointer to fs object */ + vol = get_ldnumber(&rp); + if (vol < 0) + return FR_INVALID_DRIVE; + cfs = FatFs[vol]; /* Pointer to fs object */ - if (cfs) { + if (cfs) { #if _FS_LOCK - clear_lock(cfs); + clear_lock(cfs); #endif -#if _FS_REENTRANT /* Discard sync object of the current volume */ - if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; +#if _FS_REENTRANT /* Discard sync object of the current volume */ + if (!ff_del_syncobj(cfs->sobj)) + return FR_INT_ERR; #endif - cfs->fs_type = 0; /* Clear old fs object */ - } + cfs->fs_type = 0; /* Clear old fs object */ + } - if (fs) { - fs->fs_type = 0; /* Clear new fs object */ -#if _FS_REENTRANT /* Create sync object for the new volume */ - if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; + if (fs) { + fs->fs_type = 0; /* Clear new fs object */ +#if _FS_REENTRANT /* Create sync object for the new volume */ + if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) + return FR_INT_ERR; #endif - } - FatFs[vol] = fs; /* Register new fs object */ + } + FatFs[vol] = fs; /* Register new fs object */ - if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */ + if (!fs || opt != 1) + return FR_OK; /* Do not mount now, it will be mounted later */ - res = find_volume(&fs, &path, 0); /* Force mounted the volume */ - LEAVE_FF(fs, res); + res = find_volume(&fs, &path, 0); /* Force mounted the volume */ + LEAVE_FF(fs, res); } - - - /*-----------------------------------------------------------------------*/ /* Open or Create a File */ /*-----------------------------------------------------------------------*/ -FRESULT f_open ( - FIL* fp, /* Pointer to the blank file object */ - const TCHAR* path, /* Pointer to the file name */ - BYTE mode /* Access mode and file open mode flags */ -) +FRESULT +f_open(FIL* fp, /* Pointer to the blank file object */ + const TCHAR* path, /* Pointer to the file name */ + BYTE mode /* Access mode and file open mode flags */ + ) { - FRESULT res; - DIR dj; - BYTE *dir; - DEFINE_NAMEBUF; + FRESULT res; + DIR dj; + BYTE* dir; + DEFINE_NAMEBUF; #if !_FS_READONLY - DWORD dw, cl; + DWORD dw, cl; #endif + if (!fp) + return FR_INVALID_OBJECT; + fp->fs = 0; /* Clear file object */ - if (!fp) return FR_INVALID_OBJECT; - fp->fs = 0; /* Clear file object */ - - /* Get logical drive number */ +/* Get logical drive number */ #if !_FS_READONLY - mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; - res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ)); + mode &= + FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; + res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ)); #else - mode &= FA_READ; - res = find_volume(&dj.fs, &path, 0); -#endif - if (res == FR_OK) { - INIT_BUF(dj); - res = follow_path(&dj, path); /* Follow the file path */ - dir = dj.dir; -#if !_FS_READONLY /* R/W configuration */ - if (res == FR_OK) { - if (!dir) /* Default directory itself */ - res = FR_INVALID_NAME; + mode &= FA_READ; + res = find_volume(&dj.fs, &path, 0); +#endif + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + dir = dj.dir; +#if !_FS_READONLY /* R/W configuration */ + if (res == FR_OK) { + if (!dir) /* Default directory itself */ + res = FR_INVALID_NAME; #if _FS_LOCK - else - res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); -#endif - } - /* Create or Open a file */ - if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { - if (res != FR_OK) { /* No file, create new */ - if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ + else + res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); +#endif + } + /* Create or Open a file */ + if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { + if (res != FR_OK) { /* No file, create new */ + if (res == + FR_NO_FILE) /* There is no file to open, create a new entry + */ #if _FS_LOCK - res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; + res = + enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else - res = dir_register(&dj); -#endif - mode |= FA_CREATE_ALWAYS; /* File is created */ - dir = dj.dir; /* New entry */ - } - else { /* Any object is already existing */ - if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ - res = FR_DENIED; - } else { - if (mode & FA_CREATE_NEW) /* Cannot create as new file */ - res = FR_EXIST; - } - } - if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ - dw = GET_FATTIME(); /* Created time */ - ST_DWORD(dir + DIR_CrtTime, dw); - dir[DIR_Attr] = 0; /* Reset attribute */ - ST_DWORD(dir + DIR_FileSize, 0);/* size = 0 */ - cl = ld_clust(dj.fs, dir); /* Get start cluster */ - st_clust(dir, 0); /* cluster = 0 */ - dj.fs->wflag = 1; - if (cl) { /* Remove the cluster chain if exist */ - dw = dj.fs->winsect; - res = remove_chain(dj.fs, cl); - if (res == FR_OK) { - dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ - res = move_window(dj.fs, dw); - } - } - } - } - else { /* Open an existing file */ - if (res == FR_OK) { /* Follow succeeded */ - if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ - res = FR_NO_FILE; - } else { - if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ - res = FR_DENIED; - } - } - } - if (res == FR_OK) { - if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ - mode |= FA__WRITTEN; - fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ - fp->dir_ptr = dir; + res = dir_register(&dj); +#endif + mode |= FA_CREATE_ALWAYS; /* File is created */ + dir = dj.dir; /* New entry */ + } else { /* Any object is already existing */ + if (dir[DIR_Attr] & + (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + res = FR_DENIED; + } else { + if (mode & FA_CREATE_NEW) /* Cannot create as new file */ + res = FR_EXIST; + } + } + if (res == FR_OK && + (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ + dw = GET_FATTIME(); /* Created time */ + ST_DWORD(dir + DIR_CrtTime, dw); + dir[DIR_Attr] = 0; /* Reset attribute */ + ST_DWORD(dir + DIR_FileSize, 0); /* size = 0 */ + cl = ld_clust(dj.fs, dir); /* Get start cluster */ + st_clust(dir, 0); /* cluster = 0 */ + dj.fs->wflag = 1; + if (cl) { /* Remove the cluster chain if exist */ + dw = dj.fs->winsect; + res = remove_chain(dj.fs, cl); + if (res == FR_OK) { + dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ + res = move_window(dj.fs, dw); + } + } + } + } else { /* Open an existing file */ + if (res == FR_OK) { /* Follow succeeded */ + if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ + res = FR_NO_FILE; + } else { + if ((mode & FA_WRITE) && + (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ + res = FR_DENIED; + } + } + } + if (res == FR_OK) { + if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or + overwritten */ + mode |= FA__WRITTEN; + fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dir; #if _FS_LOCK - fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); - if (!fp->lockid) res = FR_INT_ERR; -#endif - } - -#else /* R/O configuration */ - if (res == FR_OK) { /* Follow succeeded */ - dir = dj.dir; - if (!dir) { /* Current directory itself */ - res = FR_INVALID_NAME; - } else { - if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ - res = FR_NO_FILE; - } - } -#endif - FREE_BUF(); - - if (res == FR_OK) { - fp->flag = mode; /* File access mode */ - fp->err = 0; /* Clear error flag */ - fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ - fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */ - fp->fptr = 0; /* File pointer */ - fp->dsect = 0; + fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + if (!fp->lockid) + res = FR_INT_ERR; +#endif + } + +#else /* R/O configuration */ + if (res == FR_OK) { /* Follow succeeded */ + dir = dj.dir; + if (!dir) { /* Current directory itself */ + res = FR_INVALID_NAME; + } else { + if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ + res = FR_NO_FILE; + } + } +#endif + FREE_BUF(); + + if (res == FR_OK) { + fp->flag = mode; /* File access mode */ + fp->err = 0; /* Clear error flag */ + fp->sclust = ld_clust(dj.fs, dir); /* File start cluster */ + fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */ + fp->fptr = 0; /* File pointer */ + fp->dsect = 0; #if _USE_FASTSEEK - fp->cltbl = 0; /* Normal seek mode */ + fp->cltbl = 0; /* Normal seek mode */ #endif - fp->fs = dj.fs; /* Validate file object */ - fp->id = fp->fs->id; - } - } + fp->fs = dj.fs; /* Validate file object */ + fp->id = fp->fs->id; + } + } - LEAVE_FF(dj.fs, res); + LEAVE_FF(dj.fs, res); } - - - /*-----------------------------------------------------------------------*/ /* Read File */ /*-----------------------------------------------------------------------*/ -FRESULT f_read ( - FIL* fp, /* Pointer to the file object */ - void* buff, /* Pointer to data buffer */ - UINT btr, /* Number of bytes to read */ - UINT* br /* Pointer to number of bytes read */ -) +FRESULT +f_read(FIL* fp, /* Pointer to the file object */ + void* buff, /* Pointer to data buffer */ + UINT btr, /* Number of bytes to read */ + UINT* br /* Pointer to number of bytes read */ + ) { - FRESULT res; - DWORD clst, sect, remain; - UINT rcnt, cc; - BYTE csect, *rbuff = (BYTE*)buff; - - - *br = 0; /* Clear read byte counter */ - - res = validate(fp); /* Check validity */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - if (!(fp->flag & FA_READ)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - remain = fp->fsize - fp->fptr; - if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ - - for ( ; btr; /* Repeat until all data read */ - rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if (!csect) { /* On the cluster boundary? */ - if (fp->fptr == 0) { /* On the top of the file? */ - clst = fp->sclust; /* Follow from the origin */ - } else { /* Middle or end of the file */ + FRESULT res; + DWORD clst, sect, remain; + UINT rcnt, cc; + BYTE csect, *rbuff = (BYTE *)buff; + + *br = 0; /* Clear read byte counter */ + + res = validate(fp); /* Check validity */ + if (res != FR_OK) + LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_READ)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + remain = fp->fsize - fp->fptr; + if (btr > remain) + btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for (; btr; /* Repeat until all data read */ + rbuff += rcnt, fp->fptr += rcnt, * br += rcnt, btr -= rcnt) { + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + csect = + (BYTE)(fp->fptr / SS(fp->fs) & + (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->sclust; /* Follow from the origin */ + } else { /* Middle or end of the file */ #if _USE_FASTSEEK - if (fp->cltbl) - clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ - else -#endif - clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */ - } - if (clst < 2) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->clust = clst; /* Update current cluster */ - } - sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fp->fs, FR_INT_ERR); - sect += csect; - cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ - if (cc) { /* Read maximum contiguous sectors directly */ - if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ - cc = fp->fs->csize - csect; - if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); -#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ + if (fp->cltbl) + clst = clmt_clust( + fp, fp->fptr); /* Get cluster# from the CLMT */ + else +#endif + clst = get_fat( + fp->fs, + fp->clust); /* Follow cluster chain on the FAT */ + } + if (clst < 2) + ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) + ABORT(fp->fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ + if (!sect) + ABORT(fp->fs, FR_INT_ERR); + sect += csect; + cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Read maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - csect; + if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); +#if !_FS_READONLY && \ + _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if \ + it contains a dirty sector */ #if _FS_TINY - if (fp->fs->wflag && fp->fs->winsect - sect < cc) - mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs)); + if (fp->fs->wflag && fp->fs->winsect - sect < cc) + mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), + fp->fs->win, SS(fp->fs)); #else - if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) - mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); + if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) + mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, + SS(fp->fs)); #endif #endif - rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ - continue; - } + rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + continue; + } #if !_FS_TINY - if (fp->dsect != sect) { /* Load data sector if not in cache */ + if (fp->dsect != sect) { /* Load data sector if not in cache */ #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; - } -#endif - if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */ - ABORT(fp->fs, FR_DISK_ERR); - } -#endif - fp->dsect = sect; - } - rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */ - if (rcnt > btr) rcnt = btr; + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != + RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, sect, 1) != + RES_OK) /* Fill sector cache */ + ABORT(fp->fs, FR_DISK_ERR); + } +#endif + fp->dsect = sect; + } + rcnt = SS(fp->fs) - + ((UINT)fp->fptr % + SS(fp->fs)); /* Get partial sector data from sector buffer */ + if (rcnt > btr) + rcnt = btr; #if _FS_TINY - if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ - ABORT(fp->fs, FR_DISK_ERR); - mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ + if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], + rcnt); /* Pick partial sector */ #else - mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ + mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], + rcnt); /* Pick partial sector */ #endif - } + } - LEAVE_FF(fp->fs, FR_OK); + LEAVE_FF(fp->fs, FR_OK); } - - - #if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Write File */ /*-----------------------------------------------------------------------*/ -FRESULT f_write ( - FIL* fp, /* Pointer to the file object */ - const void *buff, /* Pointer to the data to be written */ - UINT btw, /* Number of bytes to write */ - UINT* bw /* Pointer to number of bytes written */ -) +FRESULT +f_write(FIL* fp, /* Pointer to the file object */ + const void* buff, /* Pointer to the data to be written */ + UINT btw, /* Number of bytes to write */ + UINT* bw /* Pointer to number of bytes written */ + ) { - FRESULT res; - DWORD clst, sect; - UINT wcnt, cc; - const BYTE *wbuff = (const BYTE*)buff; - BYTE csect; - - - *bw = 0; /* Clear write byte counter */ - - res = validate(fp); /* Check validity */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - if (!(fp->flag & FA_WRITE)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - if (fp->fptr + btw < fp->fptr) btw = 0; /* File size cannot reach 4GB */ - - for ( ; btw; /* Repeat until all data written */ - wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if (!csect) { /* On the cluster boundary? */ - if (fp->fptr == 0) { /* On the top of the file? */ - clst = fp->sclust; /* Follow from the origin */ - if (clst == 0) /* When no cluster is allocated, */ - clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ - } else { /* Middle or end of the file */ + FRESULT res; + DWORD clst, sect; + UINT wcnt, cc; + const BYTE* wbuff = (const BYTE*)buff; + BYTE csect; + + *bw = 0; /* Clear write byte counter */ + + res = validate(fp); /* Check validity */ + if (res != FR_OK) + LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_WRITE)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + if (fp->fptr + btw < fp->fptr) + btw = 0; /* File size cannot reach 4GB */ + + for (; btw; /* Repeat until all data written */ + wbuff += wcnt, fp->fptr += wcnt, * bw += wcnt, btw -= wcnt) { + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + csect = + (BYTE)(fp->fptr / SS(fp->fs) & + (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->sclust; /* Follow from the origin */ + if (clst == 0) /* When no cluster is allocated, */ + clst = create_chain(fp->fs, + 0); /* Create a new cluster chain */ + } else { /* Middle or end of the file */ #if _USE_FASTSEEK - if (fp->cltbl) - clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ - else -#endif - clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */ - } - if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ - if (clst == 1) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->clust = clst; /* Update current cluster */ - if (fp->sclust == 0) fp->sclust = clst; /* Set start cluster if the first write */ - } + if (fp->cltbl) + clst = clmt_clust( + fp, fp->fptr); /* Get cluster# from the CLMT */ + else +#endif + clst = create_chain( + fp->fs, fp->clust); /* Follow or stretch cluster + chain on the FAT */ + } + if (clst == 0) + break; /* Could not allocate a new cluster (disk full) */ + if (clst == 1) + ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) + ABORT(fp->fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + if (fp->sclust == 0) + fp->sclust = + clst; /* Set start cluster if the first write */ + } #if _FS_TINY - if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */ - ABORT(fp->fs, FR_DISK_ERR); + if (fp->fs->winsect == fp->dsect && + sync_window(fp->fs)) /* Write-back sector cache */ + ABORT(fp->fs, FR_DISK_ERR); #else - if (fp->flag & FA__DIRTY) { /* Write-back sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; - } -#endif - sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ - if (!sect) ABORT(fp->fs, FR_INT_ERR); - sect += csect; - cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ - if (cc) { /* Write maximum contiguous sectors directly */ - if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ - cc = fp->fs->csize - csect; - if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); + if (fp->flag & FA__DIRTY) { /* Write-back sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + sect = clust2sect(fp->fs, fp->clust); /* Get current sector */ + if (!sect) + ABORT(fp->fs, FR_INT_ERR); + sect += csect; + cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Write maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - csect; + if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); #if _FS_MINIMIZE <= 2 #if _FS_TINY - if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ - mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs)); - fp->fs->wflag = 0; - } + if (fp->fs->winsect - sect < + cc) { /* Refill sector cache if it gets invalidated by the + direct write */ + mem_cpy(fp->fs->win, + wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), + SS(fp->fs)); + fp->fs->wflag = 0; + } #else - if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ - mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs)); - fp->flag &= ~FA__DIRTY; - } -#endif -#endif - wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ - continue; - } + if (fp->dsect - sect < + cc) { /* Refill sector cache if it gets invalidated by the + direct write */ + mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), + SS(fp->fs)); + fp->flag &= ~FA__DIRTY; + } +#endif +#endif + wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + continue; + } #if _FS_TINY - if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */ - if (sync_window(fp->fs)) ABORT(fp->fs, FR_DISK_ERR); - fp->fs->winsect = sect; - } + if (fp->fptr >= + fp->fsize) { /* Avoid silly cache filling at growing edge */ + if (sync_window(fp->fs)) + ABORT(fp->fs, FR_DISK_ERR); + fp->fs->winsect = sect; + } #else - if (fp->dsect != sect) { /* Fill sector cache with file data */ - if (fp->fptr < fp->fsize && - disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - } -#endif - fp->dsect = sect; - } - wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */ - if (wcnt > btw) wcnt = btw; + if (fp->dsect != sect) { /* Fill sector cache with file data */ + if (fp->fptr < fp->fsize && + disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + } +#endif + fp->dsect = sect; + } + wcnt = SS(fp->fs) - + ((UINT)fp->fptr % + SS(fp->fs)); /* Put partial sector into file I/O buffer */ + if (wcnt > btw) + wcnt = btw; #if _FS_TINY - if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ - ABORT(fp->fs, FR_DISK_ERR); - mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ - fp->fs->wflag = 1; + if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, + wcnt); /* Fit partial sector */ + fp->fs->wflag = 1; #else - mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ - fp->flag |= FA__DIRTY; + mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, + wcnt); /* Fit partial sector */ + fp->flag |= FA__DIRTY; #endif - } + } - if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ - fp->flag |= FA__WRITTEN; /* Set file change flag */ + if (fp->fptr > fp->fsize) + fp->fsize = fp->fptr; /* Update file size if needed */ + fp->flag |= FA__WRITTEN; /* Set file change flag */ - LEAVE_FF(fp->fs, FR_OK); + LEAVE_FF(fp->fs, FR_OK); } - - - /*-----------------------------------------------------------------------*/ /* Synchronize the File */ /*-----------------------------------------------------------------------*/ -FRESULT f_sync ( - FIL* fp /* Pointer to the file object */ -) +FRESULT +f_sync(FIL* fp /* Pointer to the file object */ + ) { - FRESULT res; - DWORD tm; - BYTE *dir; - - - res = validate(fp); /* Check validity of the object */ - if (res == FR_OK) { - if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ - /* Write-back dirty buffer */ + FRESULT res; + DWORD tm; + BYTE* dir; + + res = validate(fp); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ + /* Write-back dirty buffer */ #if !_FS_TINY - if (fp->flag & FA__DIRTY) { - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - LEAVE_FF(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; - } -#endif - /* Update the directory entry */ - res = move_window(fp->fs, fp->dir_sect); - if (res == FR_OK) { - dir = fp->dir_ptr; - dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ - ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ - st_clust(dir, fp->sclust); /* Update start cluster */ - tm = GET_FATTIME(); /* Update updated time */ - ST_DWORD(dir + DIR_WrtTime, tm); - ST_WORD(dir + DIR_LstAccDate, 0); - fp->flag &= ~FA__WRITTEN; - fp->fs->wflag = 1; - res = sync_fs(fp->fs); - } - } - } - - LEAVE_FF(fp->fs, res); + if (fp->flag & FA__DIRTY) { + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + LEAVE_FF(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + /* Update the directory entry */ + res = move_window(fp->fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ + st_clust(dir, fp->sclust); /* Update start cluster */ + tm = GET_FATTIME(); /* Update updated time */ + ST_DWORD(dir + DIR_WrtTime, tm); + ST_WORD(dir + DIR_LstAccDate, 0); + fp->flag &= ~FA__WRITTEN; + fp->fs->wflag = 1; + res = sync_fs(fp->fs); + } + } + } + + LEAVE_FF(fp->fs, res); } #endif /* !_FS_READONLY */ - - - /*-----------------------------------------------------------------------*/ /* Close File */ /*-----------------------------------------------------------------------*/ -FRESULT f_close ( - FIL *fp /* Pointer to the file object to be closed */ -) +FRESULT +f_close(FIL* fp /* Pointer to the file object to be closed */ + ) { - FRESULT res; - + FRESULT res; #if !_FS_READONLY - res = f_sync(fp); /* Flush cached data */ - if (res == FR_OK) + res = f_sync(fp); /* Flush cached data */ + if (res == FR_OK) #endif - { - res = validate(fp); /* Lock volume */ - if (res == FR_OK) { + { + res = validate(fp); /* Lock volume */ + if (res == FR_OK) { #if _FS_REENTRANT - FATFS *fs = fp->fs; + FATFS* fs = fp->fs; #endif #if _FS_LOCK - res = dec_lock(fp->lockid); /* Decrement file open counter */ - if (res == FR_OK) + res = dec_lock(fp->lockid); /* Decrement file open counter */ + if (res == FR_OK) #endif - fp->fs = 0; /* Invalidate file object */ + fp->fs = 0; /* Invalidate file object */ #if _FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_fs(fs, FR_OK); /* Unlock volume */ #endif - } - } - return res; + } + } + return res; } - - - /*-----------------------------------------------------------------------*/ /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ #if _FS_RPATH >= 1 #if _VOLUMES >= 2 -FRESULT f_chdrive ( - const TCHAR* path /* Drive number */ -) +FRESULT +f_chdrive(const TCHAR* path /* Drive number */ + ) { - int vol; - + int vol; - vol = get_ldnumber(&path); - if (vol < 0) return FR_INVALID_DRIVE; + vol = get_ldnumber(&path); + if (vol < 0) + return FR_INVALID_DRIVE; - CurrVol = (BYTE)vol; + CurrVol = (BYTE)vol; - return FR_OK; + return FR_OK; } #endif - -FRESULT f_chdir ( - const TCHAR* path /* Pointer to the directory path */ -) +FRESULT +f_chdir(const TCHAR* path /* Pointer to the directory path */ + ) { - FRESULT res; - DIR dj; - DEFINE_NAMEBUF; - - - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 0); - if (res == FR_OK) { - INIT_BUF(dj); - res = follow_path(&dj, path); /* Follow the path */ - FREE_BUF(); - if (res == FR_OK) { /* Follow completed */ - if (!dj.dir) { - dj.fs->cdir = dj.sclust; /* Start directory itself */ - } else { - if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ - dj.fs->cdir = ld_clust(dj.fs, dj.dir); - else - res = FR_NO_PATH; /* Reached but a file */ - } - } - if (res == FR_NO_FILE) res = FR_NO_PATH; - } - - LEAVE_FF(dj.fs, res); + FRESULT res; + DIR dj; + DEFINE_NAMEBUF; + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 0); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the path */ + FREE_BUF(); + if (res == FR_OK) { /* Follow completed */ + if (!dj.dir) { + dj.fs->cdir = dj.sclust; /* Start directory itself */ + } else { + if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ + dj.fs->cdir = ld_clust(dj.fs, dj.dir); + else + res = FR_NO_PATH; /* Reached but a file */ + } + } + if (res == FR_NO_FILE) + res = FR_NO_PATH; + } + + LEAVE_FF(dj.fs, res); } - #if _FS_RPATH >= 2 -FRESULT f_getcwd ( - TCHAR* buff, /* Pointer to the directory path */ - UINT len /* Size of path */ -) +FRESULT +f_getcwd(TCHAR* buff, /* Pointer to the directory path */ + UINT len /* Size of path */ + ) { - FRESULT res; - DIR dj; - UINT i, n; - DWORD ccl; - TCHAR *tp; - FILINFO fno; - DEFINE_NAMEBUF; - - - *buff = 0; - /* Get logical drive number */ - res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */ - if (res == FR_OK) { - INIT_BUF(dj); - i = len; /* Bottom of buffer (directory stack base) */ - dj.sclust = dj.fs->cdir; /* Start to follow upper directory from current directory */ - while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ - res = dir_sdi(&dj, 1); /* Get parent directory */ - if (res != FR_OK) break; - res = dir_read(&dj, 0); - if (res != FR_OK) break; - dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */ - res = dir_sdi(&dj, 0); - if (res != FR_OK) break; - do { /* Find the entry links to the child directory */ - res = dir_read(&dj, 0); - if (res != FR_OK) break; - if (ccl == ld_clust(dj.fs, dj.dir)) break; /* Found the entry */ - res = dir_next(&dj, 0); - } while (res == FR_OK); - if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ - if (res != FR_OK) break; + FRESULT res; + DIR dj; + UINT i, n; + DWORD ccl; + TCHAR* tp; + FILINFO fno; + DEFINE_NAMEBUF; + + *buff = 0; + /* Get logical drive number */ + res = find_volume(&dj.fs, (const TCHAR**)&buff, 0); /* Get current volume */ + if (res == FR_OK) { + INIT_BUF(dj); + i = len; /* Bottom of buffer (directory stack base) */ + dj.sclust = + dj.fs->cdir; /* Start to follow upper directory from current + directory */ + while ((ccl = dj.sclust) != + 0) { /* Repeat while current directory is a sub-directory */ + res = dir_sdi(&dj, 1); /* Get parent directory */ + if (res != FR_OK) + break; + res = dir_read(&dj, 0); + if (res != FR_OK) + break; + dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) + break; + do { /* Find the entry links to the child directory */ + res = dir_read(&dj, 0); + if (res != FR_OK) + break; + if (ccl == ld_clust(dj.fs, dj.dir)) + break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) + res = FR_INT_ERR; /* It cannot be 'not found'. */ + if (res != FR_OK) + break; #if _USE_LFN - fno.lfname = buff; - fno.lfsize = i; + fno.lfname = buff; + fno.lfsize = i; #endif - get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ - tp = fno.fname; + get_fileinfo( + &dj, + &fno); /* Get the directory name and push it to the buffer */ + tp = fno.fname; #if _USE_LFN - if (*buff) tp = buff; -#endif - for (n = 0; tp[n]; n++) ; - if (i < n + 3) { - res = FR_NOT_ENOUGH_CORE; break; - } - while (n) buff[--i] = tp[--n]; - buff[--i] = '/'; - } - tp = buff; - if (res == FR_OK) { + if (*buff) + tp = buff; +#endif + for (n = 0; tp[n]; n++) + ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; + break; + } + while (n) + buff[--i] = tp[--n]; + buff[--i] = '/'; + } + tp = buff; + if (res == FR_OK) { #if _VOLUMES >= 2 - *tp++ = '0' + CurrVol; /* Put drive number */ - *tp++ = ':'; -#endif - if (i == len) { /* Root-directory */ - *tp++ = '/'; - } else { /* Sub-directroy */ - do /* Add stacked path str */ - *tp++ = buff[i++]; - while (i < len); - } - } - *tp = 0; - FREE_BUF(); - } - - LEAVE_FF(dj.fs, res); + *tp++ = '0' + CurrVol; /* Put drive number */ + *tp++ = ':'; +#endif + if (i == len) { /* Root-directory */ + *tp++ = '/'; + } else { /* Sub-directroy */ + do /* Add stacked path str */ + *tp++ = buff[i++]; + while (i < len); + } + } + *tp = 0; + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); } #endif /* _FS_RPATH >= 2 */ #endif /* _FS_RPATH >= 1 */ - - #if _FS_MINIMIZE <= 2 /*-----------------------------------------------------------------------*/ /* Seek File R/W Pointer */ /*-----------------------------------------------------------------------*/ -FRESULT f_lseek ( - FIL* fp, /* Pointer to the file object */ - DWORD ofs /* File pointer from top of file */ -) +FRESULT +f_lseek(FIL* fp, /* Pointer to the file object */ + DWORD ofs /* File pointer from top of file */ + ) { - FRESULT res; - DWORD clst, bcs, nsect, ifptr; + FRESULT res; + DWORD clst, bcs, nsect, ifptr; #if _USE_FASTSEEK - DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; + DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; #endif - - res = validate(fp); /* Check validity of the object */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); + res = validate(fp); /* Check validity of the object */ + if (res != FR_OK) + LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); #if _USE_FASTSEEK - if (fp->cltbl) { /* Fast seek */ - if (ofs == CREATE_LINKMAP) { /* Create CLMT */ - tbl = fp->cltbl; - tlen = *tbl++; ulen = 2; /* Given table size and required table size */ - cl = fp->sclust; /* Top of the chain */ - if (cl) { - do { - /* Get a fragment */ - tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ - do { - pcl = cl; ncl++; - cl = get_fat(fp->fs, cl); - if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); - if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - } while (cl == pcl + 1); - if (ulen <= tlen) { /* Store the length and top of the fragment */ - *tbl++ = ncl; *tbl++ = tcl; - } - } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */ - } - *fp->cltbl = ulen; /* Number of items used */ - if (ulen <= tlen) - *tbl = 0; /* Terminate table */ - else - res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ - - } else { /* Fast seek */ - if (ofs > fp->fsize) /* Clip offset at the file size */ - ofs = fp->fsize; - fp->fptr = ofs; /* Set file pointer */ - if (ofs) { - fp->clust = clmt_clust(fp, ofs - 1); - dsc = clust2sect(fp->fs, fp->clust); - if (!dsc) ABORT(fp->fs, FR_INT_ERR); - dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); - if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */ + if (fp->cltbl) { /* Fast seek */ + if (ofs == CREATE_LINKMAP) { /* Create CLMT */ + tbl = fp->cltbl; + tlen = *tbl++; + ulen = 2; /* Given table size and required table size */ + cl = fp->sclust; /* Top of the chain */ + if (cl) { + do { + /* Get a fragment */ + tcl = cl; + ncl = 0; + ulen += 2; /* Top, length and used items */ + do { + pcl = cl; + ncl++; + cl = get_fat(fp->fs, cl); + if (cl <= 1) + ABORT(fp->fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) + ABORT(fp->fs, FR_DISK_ERR); + } while (cl == pcl + 1); + if (ulen <= + tlen) { /* Store the length and top of the fragment */ + *tbl++ = ncl; + *tbl++ = tcl; + } + } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */ + } + *fp->cltbl = ulen; /* Number of items used */ + if (ulen <= tlen) + *tbl = 0; /* Terminate table */ + else + res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than + required */ + + } else { /* Fast seek */ + if (ofs > fp->fsize) /* Clip offset at the file size */ + ofs = fp->fsize; + fp->fptr = ofs; /* Set file pointer */ + if (ofs) { + fp->clust = clmt_clust(fp, ofs - 1); + dsc = clust2sect(fp->fs, fp->clust); + if (!dsc) + ABORT(fp->fs, FR_INT_ERR); + dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1); + if (fp->fptr % SS(fp->fs) && + dsc != fp->dsect) { /* Refill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; - } -#endif - if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */ - ABORT(fp->fs, FR_DISK_ERR); -#endif - fp->dsect = dsc; - } - } - } - } else -#endif - - /* Normal Seek */ - { - if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ + if (fp->flag & + FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != + RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != + RES_OK) /* Load current sector */ + ABORT(fp->fs, FR_DISK_ERR); +#endif + fp->dsect = dsc; + } + } + } + } else +#endif + + /* Normal Seek */ + { + if (ofs > + fp->fsize /* In read-only mode, clip offset with the file size + */ #if !_FS_READONLY - && !(fp->flag & FA_WRITE) -#endif - ) ofs = fp->fsize; - - ifptr = fp->fptr; - fp->fptr = nsect = 0; - if (ofs) { - bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ - if (ifptr > 0 && - (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ - fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ - ofs -= fp->fptr; - clst = fp->clust; - } else { /* When seek to back cluster, */ - clst = fp->sclust; /* start from the first cluster */ + && !(fp->flag & FA_WRITE) +#endif + ) + ofs = fp->fsize; + + ifptr = fp->fptr; + fp->fptr = nsect = 0; + if (ofs) { + bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / bcs >= + (ifptr - 1) / + bcs) { /* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & + ~(bcs - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clst = fp->clust; + } else { /* When seek to back cluster, */ + clst = fp->sclust; /* start from the first cluster */ #if !_FS_READONLY - if (clst == 0) { /* If no cluster chain, create a new chain */ - clst = create_chain(fp->fs, 0); - if (clst == 1) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->sclust = clst; - } -#endif - fp->clust = clst; - } - if (clst != 0) { - while (ofs > bcs) { /* Cluster following loop */ + if (clst == 0) { /* If no cluster chain, create a new chain */ + clst = create_chain(fp->fs, 0); + if (clst == 1) + ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) + ABORT(fp->fs, FR_DISK_ERR); + fp->sclust = clst; + } +#endif + fp->clust = clst; + } + if (clst != 0) { + while (ofs > bcs) { /* Cluster following loop */ #if !_FS_READONLY - if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ - clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */ - if (clst == 0) { /* When disk gets full, clip file size */ - ofs = bcs; break; - } - } else -#endif - clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */ - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR); - fp->clust = clst; - fp->fptr += bcs; - ofs -= bcs; - } - fp->fptr += ofs; - if (ofs % SS(fp->fs)) { - nsect = clust2sect(fp->fs, clst); /* Current sector */ - if (!nsect) ABORT(fp->fs, FR_INT_ERR); - nsect += ofs / SS(fp->fs); - } - } - } - if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */ + if (fp->flag & + FA_WRITE) { /* Check if in write mode or not */ + clst = create_chain( + fp->fs, clst); /* Force stretch if in write mode */ + if (clst == + 0) { /* When disk gets full, clip file size */ + ofs = bcs; + break; + } + } else +#endif + clst = + get_fat(fp->fs, clst); /* Follow cluster chain if + not in write mode */ + if (clst == 0xFFFFFFFF) + ABORT(fp->fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fp->fs->n_fatent) + ABORT(fp->fs, FR_INT_ERR); + fp->clust = clst; + fp->fptr += bcs; + ofs -= bcs; + } + fp->fptr += ofs; + if (ofs % SS(fp->fs)) { + nsect = clust2sect(fp->fs, clst); /* Current sector */ + if (!nsect) + ABORT(fp->fs, FR_INT_ERR); + nsect += ofs / SS(fp->fs); + } + } + } + if (fp->fptr % SS(fp->fs) && + nsect != fp->dsect) { /* Fill sector cache if needed */ #if !_FS_TINY #if !_FS_READONLY - if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - ABORT(fp->fs, FR_DISK_ERR); - fp->flag &= ~FA__DIRTY; - } -#endif - if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */ - ABORT(fp->fs, FR_DISK_ERR); -#endif - fp->dsect = nsect; - } + if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != + RES_OK) /* Fill sector cache */ + ABORT(fp->fs, FR_DISK_ERR); +#endif + fp->dsect = nsect; + } #if !_FS_READONLY - if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */ - fp->fsize = fp->fptr; - fp->flag |= FA__WRITTEN; - } + if (fp->fptr > + fp->fsize) { /* Set file change flag if the file size is extended */ + fp->fsize = fp->fptr; + fp->flag |= FA__WRITTEN; + } #endif - } + } - LEAVE_FF(fp->fs, res); + LEAVE_FF(fp->fs, res); } - - #if _FS_MINIMIZE <= 1 /*-----------------------------------------------------------------------*/ /* Create a Directory Object */ /*-----------------------------------------------------------------------*/ -FRESULT f_opendir ( - DIR* dp, /* Pointer to directory object to create */ - const TCHAR* path /* Pointer to the directory path */ -) +FRESULT +f_opendir(DIR* dp, /* Pointer to directory object to create */ + const TCHAR* path /* Pointer to the directory path */ + ) { - FRESULT res; - FATFS* fs; - DEFINE_NAMEBUF; - - - if (!dp) return FR_INVALID_OBJECT; - - /* Get logical drive number */ - res = find_volume(&fs, &path, 0); - if (res == FR_OK) { - dp->fs = fs; - INIT_BUF(*dp); - res = follow_path(dp, path); /* Follow the path to the directory */ - FREE_BUF(); - if (res == FR_OK) { /* Follow completed */ - if (dp->dir) { /* It is not the origin directory itself */ - if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */ - dp->sclust = ld_clust(fs, dp->dir); - else /* The object is a file */ - res = FR_NO_PATH; - } - if (res == FR_OK) { - dp->id = fs->id; - res = dir_sdi(dp, 0); /* Rewind directory */ + FRESULT res; + FATFS* fs; + DEFINE_NAMEBUF; + + if (!dp) + return FR_INVALID_OBJECT; + + /* Get logical drive number */ + res = find_volume(&fs, &path, 0); + if (res == FR_OK) { + dp->fs = fs; + INIT_BUF(*dp); + res = follow_path(dp, path); /* Follow the path to the directory */ + FREE_BUF(); + if (res == FR_OK) { /* Follow completed */ + if (dp->dir) { /* It is not the origin directory itself */ + if (dp->dir[DIR_Attr] & + AM_DIR) /* The object is a sub directory */ + dp->sclust = ld_clust(fs, dp->dir); + else /* The object is a file */ + res = FR_NO_PATH; + } + if (res == FR_OK) { + dp->id = fs->id; + res = dir_sdi(dp, 0); /* Rewind directory */ #if _FS_LOCK - if (res == FR_OK) { - if (dp->sclust) { - dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */ - if (!dp->lockid) - res = FR_TOO_MANY_OPEN_FILES; - } else { - dp->lockid = 0; /* Root directory need not to be locked */ - } - } -#endif - } - } - if (res == FR_NO_FILE) res = FR_NO_PATH; - } - if (res != FR_OK) dp->fs = 0; /* Invalidate the directory object if function faild */ - - LEAVE_FF(fs, res); + if (res == FR_OK) { + if (dp->sclust) { + dp->lockid = + inc_lock(dp, 0); /* Lock the sub directory */ + if (!dp->lockid) + res = FR_TOO_MANY_OPEN_FILES; + } else { + dp->lockid = + 0; /* Root directory need not to be locked */ + } + } +#endif + } + } + if (res == FR_NO_FILE) + res = FR_NO_PATH; + } + if (res != FR_OK) + dp->fs = 0; /* Invalidate the directory object if function faild */ + + LEAVE_FF(fs, res); } - - - /*-----------------------------------------------------------------------*/ /* Close Directory */ /*-----------------------------------------------------------------------*/ -FRESULT f_closedir ( - DIR *dp /* Pointer to the directory object to be closed */ -) +FRESULT +f_closedir(DIR* dp /* Pointer to the directory object to be closed */ + ) { - FRESULT res; - + FRESULT res; - res = validate(dp); - if (res == FR_OK) { + res = validate(dp); + if (res == FR_OK) { #if _FS_REENTRANT - FATFS *fs = dp->fs; + FATFS* fs = dp->fs; #endif #if _FS_LOCK - if (dp->lockid) /* Decrement sub-directory open counter */ - res = dec_lock(dp->lockid); - if (res == FR_OK) + if (dp->lockid) /* Decrement sub-directory open counter */ + res = dec_lock(dp->lockid); + if (res == FR_OK) #endif - dp->fs = 0; /* Invalidate directory object */ + dp->fs = 0; /* Invalidate directory object */ #if _FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_fs(fs, FR_OK); /* Unlock volume */ #endif - } - return res; + } + return res; } - - - /*-----------------------------------------------------------------------*/ /* Read Directory Entries in Sequence */ /*-----------------------------------------------------------------------*/ -FRESULT f_readdir ( - DIR* dp, /* Pointer to the open directory object */ - FILINFO* fno /* Pointer to file information to return */ -) +FRESULT +f_readdir(DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to file information to return */ + ) { - FRESULT res; - DEFINE_NAMEBUF; - - - res = validate(dp); /* Check validity of the object */ - if (res == FR_OK) { - if (!fno) { - res = dir_sdi(dp, 0); /* Rewind the directory object */ - } else { - INIT_BUF(*dp); - res = dir_read(dp, 0); /* Read an item */ - if (res == FR_NO_FILE) { /* Reached end of directory */ - dp->sect = 0; - res = FR_OK; - } - if (res == FR_OK) { /* A valid entry is found */ - get_fileinfo(dp, fno); /* Get the object information */ - res = dir_next(dp, 0); /* Increment index for next */ - if (res == FR_NO_FILE) { - dp->sect = 0; - res = FR_OK; - } - } - FREE_BUF(); - } - } - - LEAVE_FF(dp->fs, res); + FRESULT res; + DEFINE_NAMEBUF; + + res = validate(dp); /* Check validity of the object */ + if (res == FR_OK) { + if (!fno) { + res = dir_sdi(dp, 0); /* Rewind the directory object */ + } else { + INIT_BUF(*dp); + res = dir_read(dp, 0); /* Read an item */ + if (res == FR_NO_FILE) { /* Reached end of directory */ + dp->sect = 0; + res = FR_OK; + } + if (res == FR_OK) { /* A valid entry is found */ + get_fileinfo(dp, fno); /* Get the object information */ + res = dir_next(dp, 0); /* Increment index for next */ + if (res == FR_NO_FILE) { + dp->sect = 0; + res = FR_OK; + } + } + FREE_BUF(); + } + } + + LEAVE_FF(dp->fs, res); } - - #if _USE_FIND /*-----------------------------------------------------------------------*/ /* Find next file */ /*-----------------------------------------------------------------------*/ -FRESULT f_findnext ( - DIR* dp, /* Pointer to the open directory object */ - FILINFO* fno /* Pointer to the file information structure */ -) +FRESULT +f_findnext(DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to the file information structure */ + ) { - FRESULT res; + FRESULT res; - - for (;;) { - res = f_readdir(dp, fno); /* Get a directory item */ - if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ + for (;;) { + res = f_readdir(dp, fno); /* Get a directory item */ + if (res != FR_OK || !fno || !fno->fname[0]) + break; /* Terminate if any error or end of directory */ #if _USE_LFN - if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0)) break; /* Test for LFN if exist */ + if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0)) + break; /* Test for LFN if exist */ #endif - if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for SFN */ - } - return res; - + if (pattern_matching(dp->pat, fno->fname, 0, 0)) + break; /* Test for SFN */ + } + return res; } - - /*-----------------------------------------------------------------------*/ /* Find first file */ /*-----------------------------------------------------------------------*/ -FRESULT f_findfirst ( - DIR* dp, /* Pointer to the blank directory object */ - FILINFO* fno, /* Pointer to the file information structure */ - const TCHAR* path, /* Pointer to the directory to open */ - const TCHAR* pattern /* Pointer to the matching pattern */ -) +FRESULT +f_findfirst(DIR* dp, /* Pointer to the blank directory object */ + FILINFO* fno, /* Pointer to the file information structure */ + const TCHAR* path, /* Pointer to the directory to open */ + const TCHAR* pattern /* Pointer to the matching pattern */ + ) { - FRESULT res; + FRESULT res; - - dp->pat = pattern; /* Save pointer to pattern string */ - res = f_opendir(dp, path); /* Open the target directory */ - if (res == FR_OK) - res = f_findnext(dp, fno); /* Find the first item */ - return res; + dp->pat = pattern; /* Save pointer to pattern string */ + res = f_opendir(dp, path); /* Open the target directory */ + if (res == FR_OK) + res = f_findnext(dp, fno); /* Find the first item */ + return res; } -#endif /* _USE_FIND */ - - +#endif /* _USE_FIND */ #if _FS_MINIMIZE == 0 /*-----------------------------------------------------------------------*/ /* Get File Status */ /*-----------------------------------------------------------------------*/ -FRESULT f_stat ( - const TCHAR* path, /* Pointer to the file path */ - FILINFO* fno /* Pointer to file information to return */ -) +FRESULT +f_stat(const TCHAR* path, /* Pointer to the file path */ + FILINFO* fno /* Pointer to file information to return */ + ) { - FRESULT res; - DIR dj; - DEFINE_NAMEBUF; - - - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 0); - if (res == FR_OK) { - INIT_BUF(dj); - res = follow_path(&dj, path); /* Follow the file path */ - if (res == FR_OK) { /* Follow completed */ - if (dj.dir) { /* Found an object */ - if (fno) get_fileinfo(&dj, fno); - } else { /* It is root directory */ - res = FR_INVALID_NAME; - } - } - FREE_BUF(); - } - - LEAVE_FF(dj.fs, res); + FRESULT res; + DIR dj; + DEFINE_NAMEBUF; + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 0); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.dir) { /* Found an object */ + if (fno) + get_fileinfo(&dj, fno); + } else { /* It is root directory */ + res = FR_INVALID_NAME; + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); } - - #if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Get Number of Free Clusters */ /*-----------------------------------------------------------------------*/ -FRESULT f_getfree ( - const TCHAR* path, /* Path name of the logical drive number */ - DWORD* nclst, /* Pointer to a variable to return number of free clusters */ - FATFS** fatfs /* Pointer to return pointer to corresponding file system object */ -) +FRESULT +f_getfree( + const TCHAR* path, /* Path name of the logical drive number */ + DWORD* nclst, /* Pointer to a variable to return number of free clusters */ + FATFS** fatfs /* Pointer to return pointer to corresponding file system + object */ + ) { - FRESULT res; - FATFS *fs; - DWORD n, clst, sect, stat; - UINT i; - BYTE fat, *p; - - - /* Get logical drive number */ - res = find_volume(fatfs, &path, 0); - fs = *fatfs; - if (res == FR_OK) { - /* If free_clust is valid, return it without full cluster scan */ - if (fs->free_clust <= fs->n_fatent - 2) { - *nclst = fs->free_clust; - } else { - /* Get number of free clusters */ - fat = fs->fs_type; - n = 0; - if (fat == FS_FAT12) { - clst = 2; - do { - stat = get_fat(fs, clst); - if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } - if (stat == 1) { res = FR_INT_ERR; break; } - if (stat == 0) n++; - } while (++clst < fs->n_fatent); - } else { - clst = fs->n_fatent; - sect = fs->fatbase; - i = 0; p = 0; - do { - if (!i) { - res = move_window(fs, sect++); - if (res != FR_OK) break; - p = fs->win; - i = SS(fs); - } - if (fat == FS_FAT16) { - if (LD_WORD(p) == 0) n++; - p += 2; i -= 2; - } else { - if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++; - p += 4; i -= 4; - } - } while (--clst); - } - fs->free_clust = n; - fs->fsi_flag |= 1; - *nclst = n; - } - } - LEAVE_FF(fs, res); + FRESULT res; + FATFS* fs; + DWORD n, clst, sect, stat; + UINT i; + BYTE fat, *p; + + /* Get logical drive number */ + res = find_volume(fatfs, &path, 0); + fs = *fatfs; + if (res == FR_OK) { + /* If free_clust is valid, return it without full cluster scan */ + if (fs->free_clust <= fs->n_fatent - 2) { + *nclst = fs->free_clust; + } else { + /* Get number of free clusters */ + fat = fs->fs_type; + n = 0; + if (fat == FS_FAT12) { + clst = 2; + do { + stat = get_fat(fs, clst); + if (stat == 0xFFFFFFFF) { + res = FR_DISK_ERR; + break; + } + if (stat == 1) { + res = FR_INT_ERR; + break; + } + if (stat == 0) + n++; + } while (++clst < fs->n_fatent); + } else { + clst = fs->n_fatent; + sect = fs->fatbase; + i = 0; + p = 0; + do { + if (!i) { + res = move_window(fs, sect++); + if (res != FR_OK) + break; + p = fs->win; + i = SS(fs); + } + if (fat == FS_FAT16) { + if (LD_WORD(p) == 0) + n++; + p += 2; + i -= 2; + } else { + if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) + n++; + p += 4; + i -= 4; + } + } while (--clst); + } + fs->free_clust = n; + fs->fsi_flag |= 1; + *nclst = n; + } + } + LEAVE_FF(fs, res); } - - - /*-----------------------------------------------------------------------*/ /* Truncate File */ /*-----------------------------------------------------------------------*/ -FRESULT f_truncate ( - FIL* fp /* Pointer to the file object */ -) +FRESULT +f_truncate(FIL* fp /* Pointer to the file object */ + ) { - FRESULT res; - DWORD ncl; - - - res = validate(fp); /* Check validity of the object */ - if (res == FR_OK) { - if (fp->err) { /* Check error */ - res = (FRESULT)fp->err; - } else { - if (!(fp->flag & FA_WRITE)) /* Check access mode */ - res = FR_DENIED; - } - } - if (res == FR_OK) { - if (fp->fsize > fp->fptr) { - fp->fsize = fp->fptr; /* Set file size to current R/W point */ - fp->flag |= FA__WRITTEN; - if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ - res = remove_chain(fp->fs, fp->sclust); - fp->sclust = 0; - } else { /* When truncate a part of the file, remove remaining clusters */ - ncl = get_fat(fp->fs, fp->clust); - res = FR_OK; - if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (ncl == 1) res = FR_INT_ERR; - if (res == FR_OK && ncl < fp->fs->n_fatent) { - res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF); - if (res == FR_OK) res = remove_chain(fp->fs, ncl); - } - } + FRESULT res; + DWORD ncl; + + res = validate(fp); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->err) { /* Check error */ + res = (FRESULT)fp->err; + } else { + if (!(fp->flag & FA_WRITE)) /* Check access mode */ + res = FR_DENIED; + } + } + if (res == FR_OK) { + if (fp->fsize > fp->fptr) { + fp->fsize = fp->fptr; /* Set file size to current R/W point */ + fp->flag |= FA__WRITTEN; + if (fp->fptr == 0) { /* When set file size to zero, remove entire + cluster chain */ + res = remove_chain(fp->fs, fp->sclust); + fp->sclust = 0; + } else { /* When truncate a part of the file, remove remaining + clusters */ + ncl = get_fat(fp->fs, fp->clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) + res = FR_DISK_ERR; + if (ncl == 1) + res = FR_INT_ERR; + if (res == FR_OK && ncl < fp->fs->n_fatent) { + res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF); + if (res == FR_OK) + res = remove_chain(fp->fs, ncl); + } + } #if !_FS_TINY - if (res == FR_OK && (fp->flag & FA__DIRTY)) { - if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) - res = FR_DISK_ERR; - else - fp->flag &= ~FA__DIRTY; - } -#endif - } - if (res != FR_OK) fp->err = (FRESULT)res; - } - - LEAVE_FF(fp->fs, res); + if (res == FR_OK && (fp->flag & FA__DIRTY)) { + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + res = FR_DISK_ERR; + else + fp->flag &= ~FA__DIRTY; + } +#endif + } + if (res != FR_OK) + fp->err = (FRESULT)res; + } + + LEAVE_FF(fp->fs, res); } - - - /*-----------------------------------------------------------------------*/ /* Delete a File or Directory */ /*-----------------------------------------------------------------------*/ -FRESULT f_unlink ( - const TCHAR* path /* Pointer to the file or directory path */ -) +FRESULT +f_unlink(const TCHAR* path /* Pointer to the file or directory path */ + ) { - FRESULT res; - DIR dj, sdj; - BYTE *dir; - DWORD dclst = 0; - DEFINE_NAMEBUF; - - - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); - if (res == FR_OK) { - INIT_BUF(dj); - res = follow_path(&dj, path); /* Follow the file path */ - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; /* Cannot remove dot entry */ + FRESULT res; + DIR dj, sdj; + BYTE* dir; + DWORD dclst = 0; + DEFINE_NAMEBUF; + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; /* Cannot remove dot entry */ #if _FS_LOCK - if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open object */ -#endif - if (res == FR_OK) { /* The object is accessible */ - dir = dj.dir; - if (!dir) { - res = FR_INVALID_NAME; /* Cannot remove the origin directory */ - } else { - if (dir[DIR_Attr] & AM_RDO) - res = FR_DENIED; /* Cannot remove R/O object */ - } - if (res == FR_OK) { - dclst = ld_clust(dj.fs, dir); - if (dclst && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */ + if (res == FR_OK) + res = chk_lock(&dj, 2); /* Cannot remove open object */ +#endif + if (res == FR_OK) { /* The object is accessible */ + dir = dj.dir; + if (!dir) { + res = FR_INVALID_NAME; /* Cannot remove the origin directory */ + } else { + if (dir[DIR_Attr] & AM_RDO) + res = FR_DENIED; /* Cannot remove R/O object */ + } + if (res == FR_OK) { + dclst = ld_clust(dj.fs, dir); + if (dclst && + (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */ #if _FS_RPATH - if (dclst == dj.fs->cdir) { /* Is it the current directory? */ - res = FR_DENIED; - } else -#endif - { - mem_cpy(&sdj, &dj, sizeof (DIR)); /* Open the sub-directory */ - sdj.sclust = dclst; - res = dir_sdi(&sdj, 2); - if (res == FR_OK) { - res = dir_read(&sdj, 0); /* Read an item (excluding dot entries) */ - if (res == FR_OK) res = FR_DENIED; /* Not empty? (cannot remove) */ - if (res == FR_NO_FILE) res = FR_OK; /* Empty? (can remove) */ - } - } - } - } - if (res == FR_OK) { - res = dir_remove(&dj); /* Remove the directory entry */ - if (res == FR_OK && dclst) /* Remove the cluster chain if exist */ - res = remove_chain(dj.fs, dclst); - if (res == FR_OK) res = sync_fs(dj.fs); - } - } - FREE_BUF(); - } - - LEAVE_FF(dj.fs, res); + if (dclst == + dj.fs->cdir) { /* Is it the current directory? */ + res = FR_DENIED; + } else +#endif + { + mem_cpy(&sdj, &dj, + sizeof(DIR)); /* Open the sub-directory */ + sdj.sclust = dclst; + res = dir_sdi(&sdj, 2); + if (res == FR_OK) { + res = dir_read( + &sdj, + 0); /* Read an item (excluding dot entries) */ + if (res == FR_OK) + res = + FR_DENIED; /* Not empty? (cannot remove) */ + if (res == FR_NO_FILE) + res = FR_OK; /* Empty? (can remove) */ + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && + dclst) /* Remove the cluster chain if exist */ + res = remove_chain(dj.fs, dclst); + if (res == FR_OK) + res = sync_fs(dj.fs); + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); } - - - /*-----------------------------------------------------------------------*/ /* Create a Directory */ /*-----------------------------------------------------------------------*/ -FRESULT f_mkdir ( - const TCHAR* path /* Pointer to the directory path */ -) +FRESULT +f_mkdir(const TCHAR* path /* Pointer to the directory path */ + ) { - FRESULT res; - DIR dj; - BYTE *dir, n; - DWORD dsc, dcl, pcl, tm = GET_FATTIME(); - DEFINE_NAMEBUF; - - - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); - if (res == FR_OK) { - INIT_BUF(dj); - res = follow_path(&dj, path); /* Follow the file path */ - if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ - if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; - if (res == FR_NO_FILE) { /* Can create a new directory */ - dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */ - res = FR_OK; - if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ - if (dcl == 1) res = FR_INT_ERR; - if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) /* Flush FAT */ - res = sync_window(dj.fs); - if (res == FR_OK) { /* Initialize the new directory table */ - dsc = clust2sect(dj.fs, dcl); - dir = dj.fs->win; - mem_set(dir, 0, SS(dj.fs)); - mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ - dir[DIR_Name] = '.'; - dir[DIR_Attr] = AM_DIR; - ST_DWORD(dir + DIR_WrtTime, tm); - st_clust(dir, dcl); - mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */ - dir[SZ_DIRE + 1] = '.'; pcl = dj.sclust; - if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) - pcl = 0; - st_clust(dir + SZ_DIRE, pcl); - for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */ - dj.fs->winsect = dsc++; - dj.fs->wflag = 1; - res = sync_window(dj.fs); - if (res != FR_OK) break; - mem_set(dir, 0, SS(dj.fs)); - } - } - if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ - if (res != FR_OK) { - remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ - } else { - dir = dj.dir; - dir[DIR_Attr] = AM_DIR; /* Attribute */ - ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */ - st_clust(dir, dcl); /* Table start cluster */ - dj.fs->wflag = 1; - res = sync_fs(dj.fs); - } - } - FREE_BUF(); - } - - LEAVE_FF(dj.fs, res); + FRESULT res; + DIR dj; + BYTE *dir, n; + DWORD dsc, dcl, pcl, tm = GET_FATTIME(); + DEFINE_NAMEBUF; + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) + res = FR_EXIST; /* Any object with same name is already existing */ + if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_NO_FILE) { /* Can create a new directory */ + dcl = create_chain( + dj.fs, 0); /* Allocate a cluster for the new directory table */ + res = FR_OK; + if (dcl == 0) + res = FR_DENIED; /* No space to allocate a new cluster */ + if (dcl == 1) + res = FR_INT_ERR; + if (dcl == 0xFFFFFFFF) + res = FR_DISK_ERR; + if (res == FR_OK) /* Flush FAT */ + res = sync_window(dj.fs); + if (res == FR_OK) { /* Initialize the new directory table */ + dsc = clust2sect(dj.fs, dcl); + dir = dj.fs->win; + mem_set(dir, 0, SS(dj.fs)); + mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ + dir[DIR_Name] = '.'; + dir[DIR_Attr] = AM_DIR; + ST_DWORD(dir + DIR_WrtTime, tm); + st_clust(dir, dcl); + mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */ + dir[SZ_DIRE + 1] = '.'; + pcl = dj.sclust; + if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) + pcl = 0; + st_clust(dir + SZ_DIRE, pcl); + for (n = dj.fs->csize; n; + n--) { /* Write dot entries and clear following sectors */ + dj.fs->winsect = dsc++; + dj.fs->wflag = 1; + res = sync_window(dj.fs); + if (res != FR_OK) + break; + mem_set(dir, 0, SS(dj.fs)); + } + } + if (res == FR_OK) + res = + dir_register(&dj); /* Register the object to the directoy */ + if (res != FR_OK) { + remove_chain( + dj.fs, dcl); /* Could not register, remove cluster chain */ + } else { + dir = dj.dir; + dir[DIR_Attr] = AM_DIR; /* Attribute */ + ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */ + st_clust(dir, dcl); /* Table start cluster */ + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); } - - - /*-----------------------------------------------------------------------*/ /* Change Attribute */ /*-----------------------------------------------------------------------*/ -FRESULT f_chmod ( - const TCHAR* path, /* Pointer to the file path */ - BYTE attr, /* Attribute bits */ - BYTE mask /* Attribute mask to change */ -) +FRESULT +f_chmod(const TCHAR* path, /* Pointer to the file path */ + BYTE attr, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ + ) { - FRESULT res; - DIR dj; - BYTE *dir; - DEFINE_NAMEBUF; - - - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); - if (res == FR_OK) { - INIT_BUF(dj); - res = follow_path(&dj, path); /* Follow the file path */ - FREE_BUF(); - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; - if (res == FR_OK) { - dir = dj.dir; - if (!dir) { /* Is it a root directory? */ - res = FR_INVALID_NAME; - } else { /* File or sub directory */ - mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ - dir[DIR_Attr] = (attr & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ - dj.fs->wflag = 1; - res = sync_fs(dj.fs); - } - } - } - - LEAVE_FF(dj.fs, res); + FRESULT res; + DIR dj; + BYTE* dir; + DEFINE_NAMEBUF; + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + FREE_BUF(); + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_OK) { + dir = dj.dir; + if (!dir) { /* Is it a root directory? */ + res = FR_INVALID_NAME; + } else { /* File or sub directory */ + mask &= AM_RDO | AM_HID | AM_SYS | + AM_ARC; /* Valid attribute mask */ + dir[DIR_Attr] = + (attr & mask) | + (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + } + + LEAVE_FF(dj.fs, res); } - - - /*-----------------------------------------------------------------------*/ /* Rename File/Directory */ /*-----------------------------------------------------------------------*/ -FRESULT f_rename ( - const TCHAR* path_old, /* Pointer to the object to be renamed */ - const TCHAR* path_new /* Pointer to the new name */ -) +FRESULT +f_rename(const TCHAR* path_old, /* Pointer to the object to be renamed */ + const TCHAR* path_new /* Pointer to the new name */ + ) { - FRESULT res; - DIR djo, djn; - BYTE buf[21], *dir; - DWORD dw; - DEFINE_NAMEBUF; - - - /* Get logical drive number of the source object */ - res = find_volume(&djo.fs, &path_old, 1); - if (res == FR_OK) { - djn.fs = djo.fs; - INIT_BUF(djo); - res = follow_path(&djo, path_old); /* Check old object */ - if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; + FRESULT res; + DIR djo, djn; + BYTE buf[21], *dir; + DWORD dw; + DEFINE_NAMEBUF; + + /* Get logical drive number of the source object */ + res = find_volume(&djo.fs, &path_old, 1); + if (res == FR_OK) { + djn.fs = djo.fs; + INIT_BUF(djo); + res = follow_path(&djo, path_old); /* Check old object */ + if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; #if _FS_LOCK - if (res == FR_OK) res = chk_lock(&djo, 2); -#endif - if (res == FR_OK) { /* Old object is found */ - if (!djo.dir) { /* Is root dir? */ - res = FR_NO_FILE; - } else { - mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about object except name */ - mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ - if (get_ldnumber(&path_new) >= 0) /* Snip drive number off and ignore it */ - res = follow_path(&djn, path_new); /* and make sure if new object name is not conflicting */ - else - res = FR_INVALID_DRIVE; - if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ - if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ - res = dir_register(&djn); /* Register the new entry */ - if (res == FR_OK) { -/* Start of critical section where any interruption can cause a cross-link */ - dir = djn.dir; /* Copy information about object except name */ - mem_cpy(dir + 13, buf + 2, 19); - dir[DIR_Attr] = buf[0] | AM_ARC; - djo.fs->wflag = 1; - if ((dir[DIR_Attr] & AM_DIR) && djo.sclust != djn.sclust) { /* Update .. entry in the sub-directory if needed */ - dw = clust2sect(djo.fs, ld_clust(djo.fs, dir)); - if (!dw) { - res = FR_INT_ERR; - } else { - res = move_window(djo.fs, dw); - dir = djo.fs->win + SZ_DIRE * 1; /* Ptr to .. entry */ - if (res == FR_OK && dir[1] == '.') { - st_clust(dir, djn.sclust); - djo.fs->wflag = 1; - } - } - } - if (res == FR_OK) { - res = dir_remove(&djo); /* Remove old entry */ - if (res == FR_OK) - res = sync_fs(djo.fs); - } -/* End of critical section */ - } - } - } - } - FREE_BUF(); - } - - LEAVE_FF(djo.fs, res); + if (res == FR_OK) + res = chk_lock(&djo, 2); +#endif + if (res == FR_OK) { /* Old object is found */ + if (!djo.dir) { /* Is root dir? */ + res = FR_NO_FILE; + } else { + mem_cpy(buf, djo.dir + DIR_Attr, + 21); /* Save information about object except name */ + mem_cpy(&djn, &djo, + sizeof(DIR)); /* Duplicate the directory object */ + if (get_ldnumber(&path_new) >= + 0) /* Snip drive number off and ignore it */ + res = follow_path(&djn, path_new); /* and make sure if new + object name is not + conflicting */ + else + res = FR_INVALID_DRIVE; + if (res == FR_OK) + res = + FR_EXIST; /* The new object name is already existing */ + if (res == + FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + /* Start of critical section where any interruption can + * cause a cross-link */ + dir = djn.dir; /* Copy information about object except + name */ + mem_cpy(dir + 13, buf + 2, 19); + dir[DIR_Attr] = buf[0] | AM_ARC; + djo.fs->wflag = 1; + if ((dir[DIR_Attr] & AM_DIR) && + djo.sclust != + djn.sclust) { /* Update .. entry in the + sub-directory if needed */ + dw = clust2sect(djo.fs, ld_clust(djo.fs, dir)); + if (!dw) { + res = FR_INT_ERR; + } else { + res = move_window(djo.fs, dw); + dir = djo.fs->win + + SZ_DIRE * 1; /* Ptr to .. entry */ + if (res == FR_OK && dir[1] == '.') { + st_clust(dir, djn.sclust); + djo.fs->wflag = 1; + } + } + } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) + res = sync_fs(djo.fs); + } + /* End of critical section */ + } + } + } + } + FREE_BUF(); + } + + LEAVE_FF(djo.fs, res); } - - - /*-----------------------------------------------------------------------*/ /* Change Timestamp */ /*-----------------------------------------------------------------------*/ -FRESULT f_utime ( - const TCHAR* path, /* Pointer to the file/directory name */ - const FILINFO* fno /* Pointer to the time stamp to be set */ -) +FRESULT +f_utime(const TCHAR* path, /* Pointer to the file/directory name */ + const FILINFO* fno /* Pointer to the time stamp to be set */ + ) { - FRESULT res; - DIR dj; - BYTE *dir; - DEFINE_NAMEBUF; - - - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 1); - if (res == FR_OK) { - INIT_BUF(dj); - res = follow_path(&dj, path); /* Follow the file path */ - FREE_BUF(); - if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) - res = FR_INVALID_NAME; - if (res == FR_OK) { - dir = dj.dir; - if (!dir) { /* Root directory */ - res = FR_INVALID_NAME; - } else { /* File or sub-directory */ - ST_WORD(dir + DIR_WrtTime, fno->ftime); - ST_WORD(dir + DIR_WrtDate, fno->fdate); - dj.fs->wflag = 1; - res = sync_fs(dj.fs); - } - } - } - - LEAVE_FF(dj.fs, res); + FRESULT res; + DIR dj; + BYTE* dir; + DEFINE_NAMEBUF; + + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + FREE_BUF(); + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_OK) { + dir = dj.dir; + if (!dir) { /* Root directory */ + res = FR_INVALID_NAME; + } else { /* File or sub-directory */ + ST_WORD(dir + DIR_WrtTime, fno->ftime); + ST_WORD(dir + DIR_WrtDate, fno->fdate); + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + } + + LEAVE_FF(dj.fs, res); } #endif /* !_FS_READONLY */ @@ -3843,851 +4383,948 @@ FRESULT f_utime ( #endif /* _FS_MINIMIZE <= 1 */ #endif /* _FS_MINIMIZE <= 2 */ - - - #if _USE_LABEL /*-----------------------------------------------------------------------*/ /* Get volume label */ /*-----------------------------------------------------------------------*/ -FRESULT f_getlabel ( - const TCHAR* path, /* Path name of the logical drive number */ - TCHAR* label, /* Pointer to a buffer to return the volume label */ - DWORD* vsn /* Pointer to a variable to return the volume serial number */ -) +FRESULT +f_getlabel( + const TCHAR* path, /* Path name of the logical drive number */ + TCHAR* label, /* Pointer to a buffer to return the volume label */ + DWORD* vsn /* Pointer to a variable to return the volume serial number */ + ) { - FRESULT res; - DIR dj; - UINT i, j; + FRESULT res; + DIR dj; + UINT i, j; #if _USE_LFN && _LFN_UNICODE - WCHAR w; + WCHAR w; #endif + /* Get logical drive number */ + res = find_volume(&dj.fs, &path, 0); - /* Get logical drive number */ - res = find_volume(&dj.fs, &path, 0); - - /* Get volume label */ - if (res == FR_OK && label) { - dj.sclust = 0; /* Open root directory */ - res = dir_sdi(&dj, 0); - if (res == FR_OK) { - res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ - if (res == FR_OK) { /* A volume label is exist */ + /* Get volume label */ + if (res == FR_OK && label) { + dj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ + if (res == FR_OK) { /* A volume label is exist */ #if _USE_LFN && _LFN_UNICODE - i = j = 0; - do { - w = (i < 11) ? dj.dir[i++] : ' '; - if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i])) - w = w << 8 | dj.dir[i++]; - label[j++] = ff_convert(w, 1); /* OEM -> Unicode */ - } while (j < 11); + i = j = 0; + do { + w = (i < 11) ? dj.dir[i++] : ' '; + if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i])) + w = w << 8 | dj.dir[i++]; + label[j++] = ff_convert(w, 1); /* OEM -> Unicode */ + } while (j < 11); #else - mem_cpy(label, dj.dir, 11); -#endif - j = 11; - do { - label[j] = 0; - if (!j) break; - } while (label[--j] == ' '); - } - if (res == FR_NO_FILE) { /* No label, return nul string */ - label[0] = 0; - res = FR_OK; - } - } - } - - /* Get volume serial number */ - if (res == FR_OK && vsn) { - res = move_window(dj.fs, dj.fs->volbase); - if (res == FR_OK) { - i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID; - *vsn = LD_DWORD(&dj.fs->win[i]); - } - } - - LEAVE_FF(dj.fs, res); + mem_cpy(label, dj.dir, 11); +#endif + j = 11; + do { + label[j] = 0; + if (!j) + break; + } while (label[--j] == ' '); + } + if (res == FR_NO_FILE) { /* No label, return nul string */ + label[0] = 0; + res = FR_OK; + } + } + } + + /* Get volume serial number */ + if (res == FR_OK && vsn) { + res = move_window(dj.fs, dj.fs->volbase); + if (res == FR_OK) { + i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID; + *vsn = LD_DWORD(&dj.fs->win[i]); + } + } + + LEAVE_FF(dj.fs, res); } - - #if !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Set volume label */ /*-----------------------------------------------------------------------*/ -FRESULT f_setlabel ( - const TCHAR* label /* Pointer to the volume label to set */ -) +FRESULT +f_setlabel(const TCHAR* label /* Pointer to the volume label to set */ + ) { - FRESULT res; - DIR dj; - BYTE vn[11]; - UINT i, j, sl; - WCHAR w; - DWORD tm; - - - /* Get logical drive number */ - res = find_volume(&dj.fs, &label, 1); - if (res) LEAVE_FF(dj.fs, res); - - /* Create a volume label in directory form */ - vn[0] = 0; - for (sl = 0; label[sl]; sl++) ; /* Get name length */ - for ( ; sl && label[sl - 1] == ' '; sl--) ; /* Remove trailing spaces */ - if (sl) { /* Create volume label in directory form */ - i = j = 0; - do { + FRESULT res; + DIR dj; + BYTE vn[11]; + UINT i, j, sl; + WCHAR w; + DWORD tm; + + /* Get logical drive number */ + res = find_volume(&dj.fs, &label, 1); + if (res) + LEAVE_FF(dj.fs, res); + + /* Create a volume label in directory form */ + vn[0] = 0; + for (sl = 0; label[sl]; sl++) + ; /* Get name length */ + for (; sl && label[sl - 1] == ' '; sl--) + ; /* Remove trailing spaces */ + if (sl) { /* Create volume label in directory form */ + i = j = 0; + do { #if _USE_LFN && _LFN_UNICODE - w = ff_convert(ff_wtoupper(label[i++]), 0); + w = ff_convert(ff_wtoupper(label[i++]), 0); #else - w = (BYTE)label[i++]; - if (IsDBCS1(w)) - w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + w = (BYTE)label[i++]; + if (IsDBCS1(w)) + w = (j < 10 && i < sl && IsDBCS2(label[i])) + ? w << 8 | (BYTE)label[i++] + : 0; #if _USE_LFN - w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); + w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); #else - if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ + if (IsLower(w)) + w -= 0x20; /* To upper ASCII characters */ #ifdef _EXCVT - if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ + if (w >= 0x80) + w = ExCvt[w - + 0x80]; /* To upper extended characters (SBCS cfg) */ #else - if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ -#endif -#endif -#endif - if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */ - LEAVE_FF(dj.fs, FR_INVALID_NAME); - if (w >= 0x100) vn[j++] = (BYTE)(w >> 8); - vn[j++] = (BYTE)w; - } while (i < sl); - while (j < 11) vn[j++] = ' '; /* Fill remaining name field */ - if (vn[0] == DDEM) LEAVE_FF(dj.fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ - } - - /* Set volume label */ - dj.sclust = 0; /* Open root directory */ - res = dir_sdi(&dj, 0); - if (res == FR_OK) { - res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ - if (res == FR_OK) { /* A volume label is found */ - if (vn[0]) { - mem_cpy(dj.dir, vn, 11); /* Change the volume label name */ - tm = GET_FATTIME(); - ST_DWORD(dj.dir + DIR_WrtTime, tm); - } else { - dj.dir[0] = DDEM; /* Remove the volume label */ - } - dj.fs->wflag = 1; - res = sync_fs(dj.fs); - } else { /* No volume label is found or error */ - if (res == FR_NO_FILE) { - res = FR_OK; - if (vn[0]) { /* Create volume label as new */ - res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */ - if (res == FR_OK) { - mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */ - mem_cpy(dj.dir, vn, 11); - dj.dir[DIR_Attr] = AM_VOL; - tm = GET_FATTIME(); - ST_DWORD(dj.dir + DIR_WrtTime, tm); - dj.fs->wflag = 1; - res = sync_fs(dj.fs); - } - } - } - } - } - - LEAVE_FF(dj.fs, res); + if (!_DF1S && w >= 0x80) + w = 0; /* Reject extended characters (ASCII cfg) */ +#endif +#endif +#endif + if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || + j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid + characters for volume + label */ + LEAVE_FF(dj.fs, FR_INVALID_NAME); + if (w >= 0x100) + vn[j++] = (BYTE)(w >> 8); + vn[j++] = (BYTE)w; + } while (i < sl); + while (j < 11) + vn[j++] = ' '; /* Fill remaining name field */ + if (vn[0] == DDEM) + LEAVE_FF(dj.fs, + FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + } + + /* Set volume label */ + dj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Get an entry with AM_VOL */ + if (res == FR_OK) { /* A volume label is found */ + if (vn[0]) { + mem_cpy(dj.dir, vn, 11); /* Change the volume label name */ + tm = GET_FATTIME(); + ST_DWORD(dj.dir + DIR_WrtTime, tm); + } else { + dj.dir[0] = DDEM; /* Remove the volume label */ + } + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } else { /* No volume label is found or error */ + if (res == FR_NO_FILE) { + res = FR_OK; + if (vn[0]) { /* Create volume label as new */ + res = dir_alloc(&dj, + 1); /* Allocate an entry for volume label */ + if (res == FR_OK) { + mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */ + mem_cpy(dj.dir, vn, 11); + dj.dir[DIR_Attr] = AM_VOL; + tm = GET_FATTIME(); + ST_DWORD(dj.dir + DIR_WrtTime, tm); + dj.fs->wflag = 1; + res = sync_fs(dj.fs); + } + } + } + } + } + + LEAVE_FF(dj.fs, res); } #endif /* !_FS_READONLY */ #endif /* _USE_LABEL */ - - /*-----------------------------------------------------------------------*/ /* Forward data to the stream directly (available on only tiny cfg) */ /*-----------------------------------------------------------------------*/ #if _USE_FORWARD && _FS_TINY -FRESULT f_forward ( - FIL* fp, /* Pointer to the file object */ - UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ - UINT btf, /* Number of bytes to forward */ - UINT* bf /* Pointer to number of bytes forwarded */ -) +FRESULT +f_forward(FIL* fp, /* Pointer to the file object */ + UINT (*func)(const BYTE*, + UINT), /* Pointer to the streaming function */ + UINT btf, /* Number of bytes to forward */ + UINT* bf /* Pointer to number of bytes forwarded */ + ) { - FRESULT res; - DWORD remain, clst, sect; - UINT rcnt; - BYTE csect; - - - *bf = 0; /* Clear transfer byte counter */ - - res = validate(fp); /* Check validity of the object */ - if (res != FR_OK) LEAVE_FF(fp->fs, res); - if (fp->err) /* Check error */ - LEAVE_FF(fp->fs, (FRESULT)fp->err); - if (!(fp->flag & FA_READ)) /* Check access mode */ - LEAVE_FF(fp->fs, FR_DENIED); - - remain = fp->fsize - fp->fptr; - if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ - - for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */ - fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ - if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - if (!csect) { /* On the cluster boundary? */ - clst = (fp->fptr == 0) ? /* On the top of the file? */ - fp->sclust : get_fat(fp->fs, fp->clust); - if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); - if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); - fp->clust = clst; /* Update current cluster */ - } - } - sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */ - if (!sect) ABORT(fp->fs, FR_INT_ERR); - sect += csect; - if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */ - ABORT(fp->fs, FR_DISK_ERR); - fp->dsect = sect; - rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */ - if (rcnt > btf) rcnt = btf; - rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt); - if (!rcnt) ABORT(fp->fs, FR_INT_ERR); - } - - LEAVE_FF(fp->fs, FR_OK); + FRESULT res; + DWORD remain, clst, sect; + UINT rcnt; + BYTE csect; + + *bf = 0; /* Clear transfer byte counter */ + + res = validate(fp); /* Check validity of the object */ + if (res != FR_OK) + LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_READ)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + + remain = fp->fsize - fp->fptr; + if (btf > remain) + btf = (UINT)remain; /* Truncate btf by remaining bytes */ + + for (; + btf && + (*func)( + 0, + 0); /* Repeat until all data transferred or stream becomes busy */ + fp->fptr += rcnt, * bf += rcnt, btf -= rcnt) { + csect = (BYTE)(fp->fptr / SS(fp->fs) & + (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + if (!csect) { /* On the cluster boundary? */ + clst = (fp->fptr == 0) ? /* On the top of the file? */ + fp->sclust + : get_fat(fp->fs, fp->clust); + if (clst <= 1) + ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) + ABORT(fp->fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + } + sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */ + if (!sect) + ABORT(fp->fs, FR_INT_ERR); + sect += csect; + if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + fp->dsect = sect; + rcnt = + SS(fp->fs) - + (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */ + if (rcnt > btf) + rcnt = btf; + rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt); + if (!rcnt) + ABORT(fp->fs, FR_INT_ERR); + } + + LEAVE_FF(fp->fs, FR_OK); } #endif /* _USE_FORWARD */ - - #if _USE_MKFS && !_FS_READONLY /*-----------------------------------------------------------------------*/ /* Create file system on the logical drive */ /*-----------------------------------------------------------------------*/ -#define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */ -#define N_FATS 1 /* Number of FATs (1 or 2) */ - - -FRESULT f_mkfs ( - const TCHAR* path, /* Logical drive number */ - BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ - UINT au /* Size of allocation unit in unit of byte or sector */ -) +#define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */ +#define N_FATS 1 /* Number of FATs (1 or 2) */ + +FRESULT +f_mkfs(const TCHAR* path, /* Logical drive number */ + BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ + UINT au /* Size of allocation unit in unit of byte or sector */ + ) { - static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0}; - static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512}; - int vol; - BYTE fmt, md, sys, *tbl, pdrv, part; - DWORD n_clst, vs, n, wsect; - UINT i; - DWORD b_vol, b_fat, b_dir, b_data; /* LBA */ - DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ - FATFS *fs; - DSTATUS stat; + static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0 }; + static const WORD cst[] = { 32768, 16384, 8192, 4096, 2048, 16384, + 8192, 4096, 2048, 1024, 512 }; + int vol; + BYTE fmt, md, sys, *tbl, pdrv, part; + DWORD n_clst, vs, n, wsect; + UINT i; + DWORD b_vol, b_fat, b_dir, b_data; /* LBA */ + DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ + FATFS* fs; + DSTATUS stat; #if _USE_TRIM - DWORD eb[2]; -#endif - - - /* Check mounted drive and clear work area */ - if (sfd > 1) return FR_INVALID_PARAMETER; - vol = get_ldnumber(&path); - if (vol < 0) return FR_INVALID_DRIVE; - fs = FatFs[vol]; - if (!fs) return FR_NOT_ENABLED; - fs->fs_type = 0; - pdrv = LD2PD(vol); /* Physical drive */ - part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/ - - /* Get disk statics */ - stat = disk_initialize(pdrv); - if (stat & STA_NOINIT) return FR_NOT_READY; - if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; -#if _MAX_SS != _MIN_SS /* Get disk sector size */ - if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) - return FR_DISK_ERR; -#endif - if (_MULTI_PARTITION && part) { - /* Get partition information from partition table in the MBR */ - if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) return FR_DISK_ERR; - if (LD_WORD(fs->win + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; - tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; - if (!tbl[4]) return FR_MKFS_ABORTED; /* No partition? */ - b_vol = LD_DWORD(tbl + 8); /* Volume start sector */ - n_vol = LD_DWORD(tbl + 12); /* Volume size */ - } else { - /* Create a partition in this function */ - if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) - return FR_DISK_ERR; - b_vol = (sfd) ? 0 : 63; /* Volume start sector */ - n_vol -= b_vol; /* Volume size */ - } - - if (au & (au - 1)) au = 0; - if (!au) { /* AU auto selection */ - vs = n_vol / (2000 / (SS(fs) / 512)); - for (i = 0; vs < vst[i]; i++) ; - au = cst[i]; - } - if (au >= _MIN_SS) au /= SS(fs); /* Number of sectors per cluster */ - if (!au) au = 1; - if (au > 128) au = 128; - - /* Pre-compute number of clusters and FAT sub-type */ - n_clst = n_vol / au; - fmt = FS_FAT12; - if (n_clst >= MIN_FAT16) fmt = FS_FAT16; - if (n_clst >= MIN_FAT32) fmt = FS_FAT32; - - /* Determine offset and size of FAT structure */ - if (fmt == FS_FAT32) { - n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); - n_rsv = 32; - n_dir = 0; - } else { - n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; - n_fat = (n_fat + SS(fs) - 1) / SS(fs); - n_rsv = 1; - n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs); - } - b_fat = b_vol + n_rsv; /* FAT area start sector */ - b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ - b_data = b_dir + n_dir; /* Data area start sector */ - if (n_vol < b_data + au - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ - - /* Align data start sector to erase block boundary (for flash memory media) */ - if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1; - n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */ - n = (n - b_data) / N_FATS; - if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ - n_rsv += n; - b_fat += n; - } else { /* FAT12/16: Expand FAT size */ - n_fat += n; - } - - /* Determine number of clusters and final check of validity of the FAT sub-type */ - n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; - if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) - || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) - return FR_MKFS_ABORTED; - - /* Determine system ID in the partition table */ - if (fmt == FS_FAT32) { - sys = 0x0C; /* FAT32X */ - } else { - if (fmt == FS_FAT12 && n_vol < 0x10000) { - sys = 0x01; /* FAT12(<65536) */ - } else { - sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */ - } - } - - if (_MULTI_PARTITION && part) { - /* Update system ID in the partition table */ - tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; - tbl[4] = sys; - if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */ - return FR_DISK_ERR; - md = 0xF8; - } else { - if (sfd) { /* No partition table (SFD) */ - md = 0xF0; - } else { /* Create partition table (FDISK) */ - mem_set(fs->win, 0, SS(fs)); - tbl = fs->win + MBR_Table; /* Create partition table for single partition in the drive */ - tbl[1] = 1; /* Partition start head */ - tbl[2] = 1; /* Partition start sector */ - tbl[3] = 0; /* Partition start cylinder */ - tbl[4] = sys; /* System type */ - tbl[5] = 254; /* Partition end head */ - n = (b_vol + n_vol) / 63 / 255; - tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */ - tbl[7] = (BYTE)n; /* End cylinder */ - ST_DWORD(tbl + 8, 63); /* Partition start in LBA */ - ST_DWORD(tbl + 12, n_vol); /* Partition size in LBA */ - ST_WORD(fs->win + BS_55AA, 0xAA55); /* MBR signature */ - if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR */ - return FR_DISK_ERR; - md = 0xF8; - } - } - - /* Create BPB in the VBR */ - tbl = fs->win; /* Clear sector */ - mem_set(tbl, 0, SS(fs)); - mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */ - i = SS(fs); /* Sector size */ - ST_WORD(tbl + BPB_BytsPerSec, i); - tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ - ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ - tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ - i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */ - ST_WORD(tbl + BPB_RootEntCnt, i); - if (n_vol < 0x10000) { /* Number of total sectors */ - ST_WORD(tbl + BPB_TotSec16, n_vol); - } else { - ST_DWORD(tbl + BPB_TotSec32, n_vol); - } - tbl[BPB_Media] = md; /* Media descriptor */ - ST_WORD(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */ - ST_WORD(tbl + BPB_NumHeads, 255); /* Number of heads */ - ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */ - n = GET_FATTIME(); /* Use current time as VSN */ - if (fmt == FS_FAT32) { - ST_DWORD(tbl + BS_VolID32, n); /* VSN */ - ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */ - ST_DWORD(tbl + BPB_RootClus, 2); /* Root directory start cluster (2) */ - ST_WORD(tbl + BPB_FSInfo, 1); /* FSINFO record offset (VBR + 1) */ - ST_WORD(tbl + BPB_BkBootSec, 6); /* Backup boot record offset (VBR + 6) */ - tbl[BS_DrvNum32] = 0x80; /* Drive number */ - tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ - mem_cpy(tbl + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ - } else { - ST_DWORD(tbl + BS_VolID, n); /* VSN */ - ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */ - tbl[BS_DrvNum] = 0x80; /* Drive number */ - tbl[BS_BootSig] = 0x29; /* Extended boot signature */ - mem_cpy(tbl + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ - } - ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ - if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */ - return FR_DISK_ERR; - if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR + 6) */ - disk_write(pdrv, tbl, b_vol + 6, 1); - - /* Initialize FAT area */ - wsect = b_fat; - for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */ - mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ - n = md; /* Media descriptor byte */ - if (fmt != FS_FAT32) { - n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; - ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */ - } else { - n |= 0xFFFFFF00; - ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */ - ST_DWORD(tbl + 4, 0xFFFFFFFF); - ST_DWORD(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ - } - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) - return FR_DISK_ERR; - mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ - for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */ - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) - return FR_DISK_ERR; - } - } - - /* Initialize root directory */ - i = (fmt == FS_FAT32) ? au : (UINT)n_dir; - do { - if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) - return FR_DISK_ERR; - } while (--i); - -#if _USE_TRIM /* Erase data area if needed */ - { - eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1; - disk_ioctl(pdrv, CTRL_TRIM, eb); - } -#endif - - /* Create FSINFO if needed */ - if (fmt == FS_FAT32) { - ST_DWORD(tbl + FSI_LeadSig, 0x41615252); - ST_DWORD(tbl + FSI_StrucSig, 0x61417272); - ST_DWORD(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ - ST_DWORD(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */ - ST_WORD(tbl + BS_55AA, 0xAA55); - disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */ - disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */ - } - - return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; + DWORD eb[2]; +#endif + + /* Check mounted drive and clear work area */ + if (sfd > 1) + return FR_INVALID_PARAMETER; + vol = get_ldnumber(&path); + if (vol < 0) + return FR_INVALID_DRIVE; + fs = FatFs[vol]; + if (!fs) + return FR_NOT_ENABLED; + fs->fs_type = 0; + pdrv = LD2PD(vol); /* Physical drive */ + part = + LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/ + + /* Get disk statics */ + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) + return FR_NOT_READY; + if (stat & STA_PROTECT) + return FR_WRITE_PROTECTED; +#if _MAX_SS != _MIN_SS /* Get disk sector size */ + if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || + SS(fs) > _MAX_SS || SS(fs) < _MIN_SS) + return FR_DISK_ERR; +#endif + if (_MULTI_PARTITION && part) { + /* Get partition information from partition table in the MBR */ + if (disk_read(pdrv, fs->win, 0, 1) != RES_OK) + return FR_DISK_ERR; + if (LD_WORD(fs->win + BS_55AA) != 0xAA55) + return FR_MKFS_ABORTED; + tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; + if (!tbl[4]) + return FR_MKFS_ABORTED; /* No partition? */ + b_vol = LD_DWORD(tbl + 8); /* Volume start sector */ + n_vol = LD_DWORD(tbl + 12); /* Volume size */ + } else { + /* Create a partition in this function */ + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) + return FR_DISK_ERR; + b_vol = (sfd) ? 0 : 63; /* Volume start sector */ + n_vol -= b_vol; /* Volume size */ + } + + if (au & (au - 1)) + au = 0; + if (!au) { /* AU auto selection */ + vs = n_vol / (2000 / (SS(fs) / 512)); + for (i = 0; vs < vst[i]; i++) + ; + au = cst[i]; + } + if (au >= _MIN_SS) + au /= SS(fs); /* Number of sectors per cluster */ + if (!au) + au = 1; + if (au > 128) + au = 128; + + /* Pre-compute number of clusters and FAT sub-type */ + n_clst = n_vol / au; + fmt = FS_FAT12; + if (n_clst >= MIN_FAT16) + fmt = FS_FAT16; + if (n_clst >= MIN_FAT32) + fmt = FS_FAT32; + + /* Determine offset and size of FAT structure */ + if (fmt == FS_FAT32) { + n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); + n_rsv = 32; + n_dir = 0; + } else { + n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; + n_fat = (n_fat + SS(fs) - 1) / SS(fs); + n_rsv = 1; + n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs); + } + b_fat = b_vol + n_rsv; /* FAT area start sector */ + b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ + b_data = b_dir + n_dir; /* Data area start sector */ + if (n_vol < b_data + au - b_vol) + return FR_MKFS_ABORTED; /* Too small volume */ + + /* Align data start sector to erase block boundary (for flash memory media) + */ + if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) + n = 1; + n = (b_data + n - 1) & + ~(n - 1); /* Next nearest erase block from current data start */ + n = (n - b_data) / N_FATS; + if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ + n_rsv += n; + b_fat += n; + } else { /* FAT12/16: Expand FAT size */ + n_fat += n; + } + + /* Determine number of clusters and final check of validity of the FAT + * sub-type */ + n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; + if ((fmt == FS_FAT16 && n_clst < MIN_FAT16) || + (fmt == FS_FAT32 && n_clst < MIN_FAT32)) + return FR_MKFS_ABORTED; + + /* Determine system ID in the partition table */ + if (fmt == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else { + if (fmt == FS_FAT12 && n_vol < 0x10000) { + sys = 0x01; /* FAT12(<65536) */ + } else { + sys = (n_vol < 0x10000) + ? 0x04 + : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */ + } + } + + if (_MULTI_PARTITION && part) { + /* Update system ID in the partition table */ + tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE]; + tbl[4] = sys; + if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */ + return FR_DISK_ERR; + md = 0xF8; + } else { + if (sfd) { /* No partition table (SFD) */ + md = 0xF0; + } else { /* Create partition table (FDISK) */ + mem_set(fs->win, 0, SS(fs)); + tbl = fs->win + MBR_Table; /* Create partition table for single + partition in the drive */ + tbl[1] = 1; /* Partition start head */ + tbl[2] = 1; /* Partition start sector */ + tbl[3] = 0; /* Partition start cylinder */ + tbl[4] = sys; /* System type */ + tbl[5] = 254; /* Partition end head */ + n = (b_vol + n_vol) / 63 / 255; + tbl[6] = (BYTE)(n >> 2 | 63); /* Partition end sector */ + tbl[7] = (BYTE)n; /* End cylinder */ + ST_DWORD(tbl + 8, 63); /* Partition start in LBA */ + ST_DWORD(tbl + 12, n_vol); /* Partition size in LBA */ + ST_WORD(fs->win + BS_55AA, 0xAA55); /* MBR signature */ + if (disk_write(pdrv, fs->win, 0, 1) != + RES_OK) /* Write it to the MBR */ + return FR_DISK_ERR; + md = 0xF8; + } + } + + /* Create BPB in the VBR */ + tbl = fs->win; /* Clear sector */ + mem_set(tbl, 0, SS(fs)); + mem_cpy(tbl, "\xEB\xFE\x90" + "MSDOS5.0", + 11); /* Boot jump code, OEM name */ + i = SS(fs); /* Sector size */ + ST_WORD(tbl + BPB_BytsPerSec, i); + tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ + ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ + tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ + i = (fmt == FS_FAT32) ? 0 + : N_ROOTDIR; /* Number of root directory entries */ + ST_WORD(tbl + BPB_RootEntCnt, i); + if (n_vol < 0x10000) { /* Number of total sectors */ + ST_WORD(tbl + BPB_TotSec16, n_vol); + } else { + ST_DWORD(tbl + BPB_TotSec32, n_vol); + } + tbl[BPB_Media] = md; /* Media descriptor */ + ST_WORD(tbl + BPB_SecPerTrk, 63); /* Number of sectors per track */ + ST_WORD(tbl + BPB_NumHeads, 255); /* Number of heads */ + ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */ + n = GET_FATTIME(); /* Use current time as VSN */ + if (fmt == FS_FAT32) { + ST_DWORD(tbl + BS_VolID32, n); /* VSN */ + ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */ + ST_DWORD(tbl + BPB_RootClus, 2); /* Root directory start cluster (2) */ + ST_WORD(tbl + BPB_FSInfo, 1); /* FSINFO record offset (VBR + 1) */ + ST_WORD(tbl + BPB_BkBootSec, + 6); /* Backup boot record offset (VBR + 6) */ + tbl[BS_DrvNum32] = 0x80; /* Drive number */ + tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(tbl + BS_VolLab32, "NO NAME " + "FAT32 ", + 19); /* Volume label, FAT signature */ + } else { + ST_DWORD(tbl + BS_VolID, n); /* VSN */ + ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */ + tbl[BS_DrvNum] = 0x80; /* Drive number */ + tbl[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(tbl + BS_VolLab, "NO NAME " + "FAT ", + 19); /* Volume label, FAT signature */ + } + ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here + regardless of sector size) */ + if (disk_write(pdrv, tbl, b_vol, 1) != + RES_OK) /* Write it to the VBR sector */ + return FR_DISK_ERR; + if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR + 6) */ + disk_write(pdrv, tbl, b_vol + 6, 1); + + /* Initialize FAT area */ + wsect = b_fat; + for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */ + mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ + n = md; /* Media descriptor byte */ + if (fmt != FS_FAT32) { + n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; + ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */ + } else { + n |= 0xFFFFFF00; + ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */ + ST_DWORD(tbl + 4, 0xFFFFFFFF); + ST_DWORD(tbl + 8, + 0x0FFFFFFF); /* Reserve cluster #2 for root directory */ + } + if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) + return FR_DISK_ERR; + mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ + for (n = 1; n < n_fat; + n++) { /* This loop may take a time on FAT32 volume due to many + single sector writes */ + if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) + return FR_DISK_ERR; + } + } + + /* Initialize root directory */ + i = (fmt == FS_FAT32) ? au : (UINT)n_dir; + do { + if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK) + return FR_DISK_ERR; + } while (--i); + +#if _USE_TRIM /* Erase data area if needed */ + { + eb[0] = wsect; + eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1; + disk_ioctl(pdrv, CTRL_TRIM, eb); + } +#endif + + /* Create FSINFO if needed */ + if (fmt == FS_FAT32) { + ST_DWORD(tbl + FSI_LeadSig, 0x41615252); + ST_DWORD(tbl + FSI_StrucSig, 0x61417272); + ST_DWORD(tbl + FSI_Free_Count, + n_clst - 1); /* Number of free clusters */ + ST_DWORD(tbl + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + ST_WORD(tbl + BS_55AA, 0xAA55); + disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */ + disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */ + } + + return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; } - - #if _MULTI_PARTITION /*-----------------------------------------------------------------------*/ /* Create partition table on the physical drive */ /*-----------------------------------------------------------------------*/ -FRESULT f_fdisk ( - BYTE pdrv, /* Physical drive number */ - const DWORD szt[], /* Pointer to the size table for each partitions */ - void* work /* Pointer to the working buffer */ -) +FRESULT +f_fdisk(BYTE pdrv, /* Physical drive number */ + const DWORD szt[], /* Pointer to the size table for each partitions */ + void* work /* Pointer to the working buffer */ + ) { - UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; - BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; - DSTATUS stat; - DWORD sz_disk, sz_part, s_part; - - - stat = disk_initialize(pdrv); - if (stat & STA_NOINIT) return FR_NOT_READY; - if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; - if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; - - /* Determine CHS in the table regardless of the drive geometry */ - for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; - if (n == 256) n--; - e_hd = n - 1; - sz_cyl = 63 * n; - tot_cyl = sz_disk / sz_cyl; - - /* Create partition table */ - mem_set(buf, 0, _MAX_SS); - p = buf + MBR_Table; b_cyl = 0; - for (i = 0; i < 4; i++, p += SZ_PTE) { - p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; - if (!p_cyl) continue; - s_part = (DWORD)sz_cyl * b_cyl; - sz_part = (DWORD)sz_cyl * p_cyl; - if (i == 0) { /* Exclude first track of cylinder 0 */ - s_hd = 1; - s_part += 63; sz_part -= 63; - } else { - s_hd = 0; - } - e_cyl = b_cyl + p_cyl - 1; - if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; - - /* Set partition table */ - p[1] = s_hd; /* Start head */ - p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ - p[3] = (BYTE)b_cyl; /* Start cylinder */ - p[4] = 0x06; /* System type (temporary setting) */ - p[5] = e_hd; /* End head */ - p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ - p[7] = (BYTE)e_cyl; /* End cylinder */ - ST_DWORD(p + 8, s_part); /* Start sector in LBA */ - ST_DWORD(p + 12, sz_part); /* Partition size */ - - /* Next partition */ - b_cyl += p_cyl; - } - ST_WORD(p, 0xAA55); - - /* Write it to the MBR */ - return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; + UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; + BYTE s_hd, e_hd, *p, *buf = (BYTE *)work; + DSTATUS stat; + DWORD sz_disk, sz_part, s_part; + + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) + return FR_NOT_READY; + if (stat & STA_PROTECT) + return FR_WRITE_PROTECTED; + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) + return FR_DISK_ERR; + + /* Determine CHS in the table regardless of the drive geometry */ + for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) + ; + if (n == 256) + n--; + e_hd = n - 1; + sz_cyl = 63 * n; + tot_cyl = sz_disk / sz_cyl; + + /* Create partition table */ + mem_set(buf, 0, _MAX_SS); + p = buf + MBR_Table; + b_cyl = 0; + for (i = 0; i < 4; i++, p += SZ_PTE) { + p_cyl = + (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; + if (!p_cyl) + continue; + s_part = (DWORD)sz_cyl * b_cyl; + sz_part = (DWORD)sz_cyl * p_cyl; + if (i == 0) { /* Exclude first track of cylinder 0 */ + s_hd = 1; + s_part += 63; + sz_part -= 63; + } else { + s_hd = 0; + } + e_cyl = b_cyl + p_cyl - 1; + if (e_cyl >= tot_cyl) + return FR_INVALID_PARAMETER; + + /* Set partition table */ + p[1] = s_hd; /* Start head */ + p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ + p[3] = (BYTE)b_cyl; /* Start cylinder */ + p[4] = 0x06; /* System type (temporary setting) */ + p[5] = e_hd; /* End head */ + p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ + p[7] = (BYTE)e_cyl; /* End cylinder */ + ST_DWORD(p + 8, s_part); /* Start sector in LBA */ + ST_DWORD(p + 12, sz_part); /* Partition size */ + + /* Next partition */ + b_cyl += p_cyl; + } + ST_WORD(p, 0xAA55); + + /* Write it to the MBR */ + return (disk_write(pdrv, buf, 0, 1) != RES_OK || + disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) + ? FR_DISK_ERR + : FR_OK; } - #endif /* _MULTI_PARTITION */ #endif /* _USE_MKFS && !_FS_READONLY */ - - - #if _USE_STRFUNC /*-----------------------------------------------------------------------*/ /* Get a string from the file */ /*-----------------------------------------------------------------------*/ -TCHAR* f_gets ( - TCHAR* buff, /* Pointer to the string buffer to read */ - int len, /* Size of string buffer (characters) */ - FIL* fp /* Pointer to the file object */ -) +TCHAR* +f_gets(TCHAR* buff, /* Pointer to the string buffer to read */ + int len, /* Size of string buffer (characters) */ + FIL* fp /* Pointer to the file object */ + ) { - int n = 0; - TCHAR c, *p = buff; - BYTE s[2]; - UINT rc; - + int n = 0; + TCHAR c, *p = buff; + BYTE s[2]; + UINT rc; - while (n < len - 1) { /* Read characters until buffer gets filled */ + while (n < len - 1) { /* Read characters until buffer gets filled */ #if _USE_LFN && _LFN_UNICODE -#if _STRF_ENCODE == 3 /* Read a character in UTF-8 */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; - c = s[0]; - if (c >= 0x80) { - if (c < 0xC0) continue; /* Skip stray trailer */ - if (c < 0xE0) { /* Two-byte sequence */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; - c = (c & 0x1F) << 6 | (s[0] & 0x3F); - if (c < 0x80) c = '?'; - } else { - if (c < 0xF0) { /* Three-byte sequence */ - f_read(fp, s, 2, &rc); - if (rc != 2) break; - c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); - if (c < 0x800) c = '?'; - } else { /* Reject four-byte sequence */ - c = '?'; - } - } - } -#elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */ - f_read(fp, s, 2, &rc); - if (rc != 2) break; - c = s[1] + (s[0] << 8); -#elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */ - f_read(fp, s, 2, &rc); - if (rc != 2) break; - c = s[0] + (s[1] << 8); -#else /* Read a character in ANSI/OEM */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; - c = s[0]; - if (IsDBCS1(c)) { - f_read(fp, s, 1, &rc); - if (rc != 1) break; - c = (c << 8) + s[0]; - } - c = ff_convert(c, 1); /* OEM -> Unicode */ - if (!c) c = '?'; -#endif -#else /* Read a character without conversion */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; - c = s[0]; -#endif - if (_USE_STRFUNC == 2 && c == '\r') continue; /* Strip '\r' */ - *p++ = c; - n++; - if (c == '\n') break; /* Break on EOL */ - } - *p = 0; - return n ? buff : 0; /* When no data read (eof or error), return with error. */ +#if _STRF_ENCODE == 3 /* Read a character in UTF-8 */ + f_read(fp, s, 1, &rc); + if (rc != 1) + break; + c = s[0]; + if (c >= 0x80) { + if (c < 0xC0) + continue; /* Skip stray trailer */ + if (c < 0xE0) { /* Two-byte sequence */ + f_read(fp, s, 1, &rc); + if (rc != 1) + break; + c = (c & 0x1F) << 6 | (s[0] & 0x3F); + if (c < 0x80) + c = '?'; + } else { + if (c < 0xF0) { /* Three-byte sequence */ + f_read(fp, s, 2, &rc); + if (rc != 2) + break; + c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); + if (c < 0x800) + c = '?'; + } else { /* Reject four-byte sequence */ + c = '?'; + } + } + } +#elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */ + f_read(fp, s, 2, &rc); + if (rc != 2) + break; + c = s[1] + (s[0] << 8); +#elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */ + f_read(fp, s, 2, &rc); + if (rc != 2) + break; + c = s[0] + (s[1] << 8); +#else /* Read a character in ANSI/OEM */ + f_read(fp, s, 1, &rc); + if (rc != 1) + break; + c = s[0]; + if (IsDBCS1(c)) { + f_read(fp, s, 1, &rc); + if (rc != 1) + break; + c = (c << 8) + s[0]; + } + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) + c = '?'; +#endif +#else /* Read a character without conversion */ + f_read(fp, s, 1, &rc); + if (rc != 1) + break; + c = s[0]; +#endif + if (_USE_STRFUNC == 2 && c == '\r') + continue; /* Strip '\r' */ + *p++ = c; + n++; + if (c == '\n') + break; /* Break on EOL */ + } + *p = 0; + return n ? buff + : 0; /* When no data read (eof or error), return with error. */ } - - - #if !_FS_READONLY #include /*-----------------------------------------------------------------------*/ /* Put a character to the file */ /*-----------------------------------------------------------------------*/ -typedef struct { - FIL* fp; - int idx, nchr; - BYTE buf[64]; +typedef struct +{ + FIL* fp; + int idx, nchr; + BYTE buf[64]; } putbuff; - -static -void putc_bfd ( - putbuff* pb, - TCHAR c -) +static void +putc_bfd(putbuff* pb, TCHAR c) { - UINT bw; - int i; - + UINT bw; + int i; - if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */ - putc_bfd(pb, '\r'); + if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */ + putc_bfd(pb, '\r'); - i = pb->idx; /* Buffer write index (-1:error) */ - if (i < 0) return; + i = pb->idx; /* Buffer write index (-1:error) */ + if (i < 0) + return; #if _USE_LFN && _LFN_UNICODE -#if _STRF_ENCODE == 3 /* Write a character in UTF-8 */ - if (c < 0x80) { /* 7-bit */ - pb->buf[i++] = (BYTE)c; - } else { - if (c < 0x800) { /* 11-bit */ - pb->buf[i++] = (BYTE)(0xC0 | c >> 6); - } else { /* 16-bit */ - pb->buf[i++] = (BYTE)(0xE0 | c >> 12); - pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F)); - } - pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F)); - } -#elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */ - pb->buf[i++] = (BYTE)(c >> 8); - pb->buf[i++] = (BYTE)c; -#elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */ - pb->buf[i++] = (BYTE)c; - pb->buf[i++] = (BYTE)(c >> 8); -#else /* Write a character in ANSI/OEM */ - c = ff_convert(c, 0); /* Unicode -> OEM */ - if (!c) c = '?'; - if (c >= 0x100) - pb->buf[i++] = (BYTE)(c >> 8); - pb->buf[i++] = (BYTE)c; -#endif -#else /* Write a character without conversion */ - pb->buf[i++] = (BYTE)c; -#endif - - if (i >= (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */ - f_write(pb->fp, pb->buf, (UINT)i, &bw); - i = (bw == (UINT)i) ? 0 : -1; - } - pb->idx = i; - pb->nchr++; +#if _STRF_ENCODE == 3 /* Write a character in UTF-8 */ + if (c < 0x80) { /* 7-bit */ + pb->buf[i++] = (BYTE)c; + } else { + if (c < 0x800) { /* 11-bit */ + pb->buf[i++] = (BYTE)(0xC0 | c >> 6); + } else { /* 16-bit */ + pb->buf[i++] = (BYTE)(0xE0 | c >> 12); + pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F)); + } + pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F)); + } +#elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */ + pb->buf[i++] = (BYTE)(c >> 8); + pb->buf[i++] = (BYTE)c; +#elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */ + pb->buf[i++] = (BYTE)c; + pb->buf[i++] = (BYTE)(c >> 8); +#else /* Write a character in ANSI/OEM */ + c = ff_convert(c, 0); /* Unicode -> OEM */ + if (!c) + c = '?'; + if (c >= 0x100) + pb->buf[i++] = (BYTE)(c >> 8); + pb->buf[i++] = (BYTE)c; +#endif +#else /* Write a character without conversion */ + pb->buf[i++] = (BYTE)c; +#endif + + if (i >= + (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */ + f_write(pb->fp, pb->buf, (UINT)i, &bw); + i = (bw == (UINT)i) ? 0 : -1; + } + pb->idx = i; + pb->nchr++; } - - -int f_putc ( - TCHAR c, /* A character to be output */ - FIL* fp /* Pointer to the file object */ -) +int +f_putc(TCHAR c, /* A character to be output */ + FIL* fp /* Pointer to the file object */ + ) { - putbuff pb; - UINT nw; + putbuff pb; + UINT nw; + pb.fp = fp; /* Initialize output buffer */ + pb.nchr = pb.idx = 0; - pb.fp = fp; /* Initialize output buffer */ - pb.nchr = pb.idx = 0; + putc_bfd(&pb, c); /* Put a character */ - putc_bfd(&pb, c); /* Put a character */ - - if ( pb.idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK - && (UINT)pb.idx == nw) return pb.nchr; - return EOF; + if (pb.idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK && + (UINT)pb.idx == nw) + return pb.nchr; + return EOF; } - - - /*-----------------------------------------------------------------------*/ /* Put a string to the file */ /*-----------------------------------------------------------------------*/ -int f_puts ( - const TCHAR* str, /* Pointer to the string to be output */ - FIL* fp /* Pointer to the file object */ -) +int +f_puts(const TCHAR* str, /* Pointer to the string to be output */ + FIL* fp /* Pointer to the file object */ + ) { - putbuff pb; - UINT nw; + putbuff pb; + UINT nw; + pb.fp = fp; /* Initialize output buffer */ + pb.nchr = pb.idx = 0; - pb.fp = fp; /* Initialize output buffer */ - pb.nchr = pb.idx = 0; + while (*str) /* Put the string */ + putc_bfd(&pb, *str++); - while (*str) /* Put the string */ - putc_bfd(&pb, *str++); - - if ( pb.idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK - && (UINT)pb.idx == nw) return pb.nchr; - return EOF; + if (pb.idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK && + (UINT)pb.idx == nw) + return pb.nchr; + return EOF; } - - - /*-----------------------------------------------------------------------*/ /* Put a formatted string to the file */ /*-----------------------------------------------------------------------*/ -int f_printf ( - FIL* fp, /* Pointer to the file object */ - const TCHAR* fmt, /* Pointer to the format string */ - ... /* Optional arguments... */ -) +int +f_printf(FIL* fp, /* Pointer to the file object */ + const TCHAR* fmt, /* Pointer to the format string */ + ... /* Optional arguments... */ + ) { - va_list arp; - BYTE f, r; - UINT nw, i, j, w; - DWORD v; - TCHAR c, d, s[16], *p; - putbuff pb; - - - pb.fp = fp; /* Initialize output buffer */ - pb.nchr = pb.idx = 0; - - va_start(arp, fmt); - - for (;;) { - c = *fmt++; - if (c == 0) break; /* End of string */ - if (c != '%') { /* Non escape character */ - putc_bfd(&pb, c); - continue; - } - w = f = 0; - c = *fmt++; - if (c == '0') { /* Flag: '0' padding */ - f = 1; c = *fmt++; - } else { - if (c == '-') { /* Flag: left justified */ - f = 2; c = *fmt++; - } - } - while (IsDigit(c)) { /* Precision */ - w = w * 10 + c - '0'; - c = *fmt++; - } - if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ - f |= 4; c = *fmt++; - } - if (!c) break; - d = c; - if (IsLower(d)) d -= 0x20; - switch (d) { /* Type is... */ - case 'S' : /* String */ - p = va_arg(arp, TCHAR*); - for (j = 0; p[j]; j++) ; - if (!(f & 2)) { - while (j++ < w) putc_bfd(&pb, ' '); - } - while (*p) putc_bfd(&pb, *p++); - while (j++ < w) putc_bfd(&pb, ' '); - continue; - case 'C' : /* Character */ - putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; - case 'B' : /* Binary */ - r = 2; break; - case 'O' : /* Octal */ - r = 8; break; - case 'D' : /* Signed decimal */ - case 'U' : /* Unsigned decimal */ - r = 10; break; - case 'X' : /* Hexdecimal */ - r = 16; break; - default: /* Unknown type (pass-through) */ - putc_bfd(&pb, c); continue; - } - - /* Get an argument and put it in numeral */ - v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); - if (d == 'D' && (v & 0x80000000)) { - v = 0 - v; - f |= 8; - } - i = 0; - do { - d = (TCHAR)(v % r); v /= r; - if (d > 9) d += (c == 'x') ? 0x27 : 0x07; - s[i++] = d + '0'; - } while (v && i < sizeof s / sizeof s[0]); - if (f & 8) s[i++] = '-'; - j = i; d = (f & 1) ? '0' : ' '; - while (!(f & 2) && j++ < w) putc_bfd(&pb, d); - do putc_bfd(&pb, s[--i]); while (i); - while (j++ < w) putc_bfd(&pb, d); - } - - va_end(arp); - - if ( pb.idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK - && (UINT)pb.idx == nw) return pb.nchr; - return EOF; + va_list arp; + BYTE f, r; + UINT nw, i, j, w; + DWORD v; + TCHAR c, d, s[16], *p; + putbuff pb; + + pb.fp = fp; /* Initialize output buffer */ + pb.nchr = pb.idx = 0; + + va_start(arp, fmt); + + for (;;) { + c = *fmt++; + if (c == 0) + break; /* End of string */ + if (c != '%') { /* Non escape character */ + putc_bfd(&pb, c); + continue; + } + w = f = 0; + c = *fmt++; + if (c == '0') { /* Flag: '0' padding */ + f = 1; + c = *fmt++; + } else { + if (c == '-') { /* Flag: left justified */ + f = 2; + c = *fmt++; + } + } + while (IsDigit(c)) { /* Precision */ + w = w * 10 + c - '0'; + c = *fmt++; + } + if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ + f |= 4; + c = *fmt++; + } + if (!c) + break; + d = c; + if (IsLower(d)) + d -= 0x20; + switch (d) { /* Type is... */ + case 'S': /* String */ + p = va_arg(arp, TCHAR*); + for (j = 0; p[j]; j++) + ; + if (!(f & 2)) { + while (j++ < w) + putc_bfd(&pb, ' '); + } + while (*p) + putc_bfd(&pb, *p++); + while (j++ < w) + putc_bfd(&pb, ' '); + continue; + case 'C': /* Character */ + putc_bfd(&pb, (TCHAR)va_arg(arp, int)); + continue; + case 'B': /* Binary */ + r = 2; + break; + case 'O': /* Octal */ + r = 8; + break; + case 'D': /* Signed decimal */ + case 'U': /* Unsigned decimal */ + r = 10; + break; + case 'X': /* Hexdecimal */ + r = 16; + break; + default: /* Unknown type (pass-through) */ + putc_bfd(&pb, c); + continue; + } + + /* Get an argument and put it in numeral */ + v = (f & 4) ? (DWORD)va_arg(arp, long) + : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) + : (DWORD)va_arg(arp, unsigned int)); + if (d == 'D' && (v & 0x80000000)) { + v = 0 - v; + f |= 8; + } + i = 0; + do { + d = (TCHAR)(v % r); + v /= r; + if (d > 9) + d += (c == 'x') ? 0x27 : 0x07; + s[i++] = d + '0'; + } while (v && i < sizeof s / sizeof s[0]); + if (f & 8) + s[i++] = '-'; + j = i; + d = (f & 1) ? '0' : ' '; + while (!(f & 2) && j++ < w) + putc_bfd(&pb, d); + do + putc_bfd(&pb, s[--i]); + while (i); + while (j++ < w) + putc_bfd(&pb, d); + } + + va_end(arp); + + if (pb.idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK && + (UINT)pb.idx == nw) + return pb.nchr; + return EOF; } #endif /* !_FS_READONLY */ diff --git a/source/fatfs/ff.h b/source/fatfs/ff.h index 22f1810..31960b4 100644 --- a/source/fatfs/ff.h +++ b/source/fatfs/ff.h @@ -15,54 +15,52 @@ / by use of this software. /---------------------------------------------------------------------------*/ - #ifndef _FATFS -#define _FATFS 32020 /* Revision ID */ +#define _FATFS 32020 /* Revision ID */ #ifdef __cplusplus extern "C" { #endif -#include "integer.h" /* Basic integer types */ -#include "ffconf.h" /* FatFs configuration options */ +#include "integer.h" /* Basic integer types */ +#include "ffconf.h" /* FatFs configuration options */ #if _FATFS != _FFCONF #error Wrong configuration file (ffconf.h). #endif - - /* Definitions of volume management */ -#if _MULTI_PARTITION /* Multiple partition configuration */ -typedef struct { - BYTE pd; /* Physical drive number */ - BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ +#if _MULTI_PARTITION /* Multiple partition configuration */ +typedef struct +{ + BYTE pd; /* Physical drive number */ + BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ } PARTITION; -extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ -#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ -#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ +extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ +#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ +#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ -#else /* Single partition configuration */ -#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ -#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ +#else /* Single partition configuration */ +#define LD2PD(vol) \ + (BYTE)(vol) /* Each logical drive is bound to the same physical drive \ + number */ +#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ #endif - - /* Type of path name strings on FatFs API */ -#if _LFN_UNICODE /* Unicode string */ +#if _LFN_UNICODE /* Unicode string */ #if !_USE_LFN #error _LFN_UNICODE must be 0 at non-LFN cfg. #endif #ifndef _INC_TCHAR typedef WCHAR TCHAR; -#define _T(x) L ## x -#define _TEXT(x) L ## x +#define _T(x) L##x +#define _TEXT(x) L##x #endif -#else /* ANSI/OEM string */ +#else /* ANSI/OEM string */ #ifndef _INC_TCHAR typedef char TCHAR; #define _T(x) x @@ -71,176 +69,192 @@ typedef char TCHAR; #endif - - /* File system object structure (FATFS) */ -typedef struct { - BYTE fs_type; /* FAT sub-type (0:Not mounted) */ - BYTE drv; /* Physical drive number */ - BYTE csize; /* Sectors per cluster (1,2,4...128) */ - BYTE n_fats; /* Number of FAT copies (1 or 2) */ - BYTE wflag; /* win[] flag (b0:dirty) */ - BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ - WORD id; /* File system mount ID */ - WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ +typedef struct +{ + BYTE fs_type; /* FAT sub-type (0:Not mounted) */ + BYTE drv; /* Physical drive number */ + BYTE csize; /* Sectors per cluster (1,2,4...128) */ + BYTE n_fats; /* Number of FAT copies (1 or 2) */ + BYTE wflag; /* win[] flag (b0:dirty) */ + BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ + WORD id; /* File system mount ID */ + WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ #if _MAX_SS != _MIN_SS - WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ + WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ #endif #if _FS_REENTRANT - _SYNC_t sobj; /* Identifier of sync object */ + _SYNC_t sobj; /* Identifier of sync object */ #endif #if !_FS_READONLY - DWORD last_clust; /* Last allocated cluster */ - DWORD free_clust; /* Number of free clusters */ + DWORD last_clust; /* Last allocated cluster */ + DWORD free_clust; /* Number of free clusters */ #endif #if _FS_RPATH - DWORD cdir; /* Current directory start cluster (0:root) */ + DWORD cdir; /* Current directory start cluster (0:root) */ #endif - DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ - DWORD fsize; /* Sectors per FAT */ - DWORD volbase; /* Volume start sector */ - DWORD fatbase; /* FAT start sector */ - DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ - DWORD database; /* Data start sector */ - DWORD winsect; /* Current sector appearing in the win[] */ - BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ + DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ + DWORD fsize; /* Sectors per FAT */ + DWORD volbase; /* Volume start sector */ + DWORD fatbase; /* FAT start sector */ + DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ + DWORD database; /* Data start sector */ + DWORD winsect; /* Current sector appearing in the win[] */ + BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data + at tiny cfg) */ } FATFS; - - /* File object structure (FIL) */ -typedef struct { - FATFS* fs; /* Pointer to the related file system object (**do not change order**) */ - WORD id; /* Owner file system mount ID (**do not change order**) */ - BYTE flag; /* Status flags */ - BYTE err; /* Abort flag (error code) */ - DWORD fptr; /* File read/write pointer (Zeroed on file open) */ - DWORD fsize; /* File size */ - DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */ - DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ - DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ +typedef struct +{ + FATFS* fs; /* Pointer to the related file system object (**do not change + order**) */ + WORD id; /* Owner file system mount ID (**do not change order**) */ + BYTE flag; /* Status flags */ + BYTE err; /* Abort flag (error code) */ + DWORD fptr; /* File read/write pointer (Zeroed on file open) */ + DWORD fsize; /* File size */ + DWORD + sclust; /* File start cluster (0:no cluster chain, always 0 when fsize + is 0) */ + DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ + DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ #if !_FS_READONLY - DWORD dir_sect; /* Sector number containing the directory entry */ - BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ + DWORD dir_sect; /* Sector number containing the directory entry */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ #endif #if _USE_FASTSEEK - DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ + DWORD* + cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ #endif #if _FS_LOCK - UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table + Files[]) */ #endif #if !_FS_TINY - BYTE buf[_MAX_SS]; /* File private data read/write window */ + BYTE buf[_MAX_SS]; /* File private data read/write window */ #endif } FIL; - - /* Directory object structure (DIR) */ -typedef struct { - FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */ - WORD id; /* Owner file system mount ID (**do not change order**) */ - WORD index; /* Current read/write index number */ - DWORD sclust; /* Table start cluster (0:Root dir) */ - DWORD clust; /* Current cluster */ - DWORD sect; /* Current sector */ - BYTE* dir; /* Pointer to the current SFN entry in the win[] */ - BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ +typedef struct +{ + FATFS* fs; /* Pointer to the owner file system object (**do not change + order**) */ + WORD id; /* Owner file system mount ID (**do not change order**) */ + WORD index; /* Current read/write index number */ + DWORD sclust; /* Table start cluster (0:Root dir) */ + DWORD clust; /* Current cluster */ + DWORD sect; /* Current sector */ + BYTE* dir; /* Pointer to the current SFN entry in the win[] */ + BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ #if _FS_LOCK - UINT lockid; /* File lock ID (index of file semaphore table Files[]) */ + UINT lockid; /* File lock ID (index of file semaphore table Files[]) */ #endif #if _USE_LFN - WCHAR* lfn; /* Pointer to the LFN working buffer */ - WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ + WCHAR* lfn; /* Pointer to the LFN working buffer */ + WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ #endif #if _USE_FIND - const TCHAR* pat; /* Pointer to the name matching pattern */ + const TCHAR* pat; /* Pointer to the name matching pattern */ #endif } DIR; - - /* File information structure (FILINFO) */ -typedef struct { - DWORD fsize; /* File size */ - WORD fdate; /* Last modified date */ - WORD ftime; /* Last modified time */ - BYTE fattrib; /* Attribute */ - TCHAR fname[13]; /* Short file name (8.3 format) */ +typedef struct +{ + DWORD fsize; /* File size */ + WORD fdate; /* Last modified date */ + WORD ftime; /* Last modified time */ + BYTE fattrib; /* Attribute */ + TCHAR fname[13]; /* Short file name (8.3 format) */ #if _USE_LFN - TCHAR* lfname; /* Pointer to the LFN buffer */ - UINT lfsize; /* Size of LFN buffer in TCHAR */ + TCHAR* lfname; /* Pointer to the LFN buffer */ + UINT lfsize; /* Size of LFN buffer in TCHAR */ #endif } FILINFO; - - /* File function return code (FRESULT) */ typedef enum { - FR_OK = 0, /* (0) Succeeded */ - FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ - FR_INT_ERR, /* (2) Assertion failed */ - FR_NOT_READY, /* (3) The physical drive cannot work */ - FR_NO_FILE, /* (4) Could not find the file */ - FR_NO_PATH, /* (5) Could not find the path */ - FR_INVALID_NAME, /* (6) The path name format is invalid */ - FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ - FR_EXIST, /* (8) Access denied due to prohibited access */ - FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ - FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ - FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ - FR_NOT_ENABLED, /* (12) The volume has no work area */ - FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ - FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ - FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ - FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ - FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ - FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ - FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ + FR_OK = 0, /* (0) Succeeded */ + FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ + FR_INT_ERR, /* (2) Assertion failed */ + FR_NOT_READY, /* (3) The physical drive cannot work */ + FR_NO_FILE, /* (4) Could not find the file */ + FR_NO_PATH, /* (5) Could not find the path */ + FR_INVALID_NAME, /* (6) The path name format is invalid */ + FR_DENIED, /* (7) Access denied due to prohibited access or directory full + */ + FR_EXIST, /* (8) Access denied due to prohibited access */ + FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ + FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ + FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ + FR_NOT_ENABLED, /* (12) The volume has no work area */ + FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ + FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ + FR_TIMEOUT, /* (15) Could not get a grant to access the volume within + defined period */ + FR_LOCKED, /* (16) The operation is rejected according to the file sharing + policy */ + FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ + FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ + FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ } FRESULT; - - /*--------------------------------------------------------------*/ /* FatFs module application interface */ -FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ -FRESULT f_close (FIL* fp); /* Close an open file object */ -FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ -FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ -FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */ -FRESULT f_truncate (FIL* fp); /* Truncate file */ -FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ -FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ -FRESULT f_closedir (DIR* dp); /* Close an open directory */ -FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ -FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ -FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ -FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ -FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ -FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ -FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ -FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ -FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */ -FRESULT f_chdir (const TCHAR* path); /* Change current directory */ -FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ -FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ -FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ -FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ -FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ -FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ -FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ -FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ -int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ -int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ -int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ -TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ +FRESULT f_open(FIL* fp, const TCHAR* path, + BYTE mode); /* Open or create a file */ +FRESULT f_close(FIL* fp); /* Close an open file object */ +FRESULT f_read(FIL* fp, void* buff, UINT btr, + UINT* br); /* Read data from a file */ +FRESULT f_write(FIL* fp, const void* buff, UINT btw, + UINT* bw); /* Write data to a file */ +FRESULT f_forward(FIL* fp, UINT (*func)(const BYTE*, UINT), UINT btf, + UINT* bf); /* Forward data to the stream */ +FRESULT f_lseek(FIL* fp, DWORD ofs); /* Move file pointer of a file object */ +FRESULT f_truncate(FIL* fp); /* Truncate file */ +FRESULT f_sync(FIL* fp); /* Flush cached data of a writing file */ +FRESULT f_opendir(DIR* dp, const TCHAR* path); /* Open a directory */ +FRESULT f_closedir(DIR* dp); /* Close an open directory */ +FRESULT f_readdir(DIR* dp, FILINFO* fno); /* Read a directory item */ +FRESULT f_findfirst(DIR* dp, FILINFO* fno, const TCHAR* path, + const TCHAR* pattern); /* Find first file */ +FRESULT f_findnext(DIR* dp, FILINFO* fno); /* Find next file */ +FRESULT f_mkdir(const TCHAR* path); /* Create a sub directory */ +FRESULT f_unlink(const TCHAR* path); /* Delete an existing file or directory */ +FRESULT f_rename(const TCHAR* path_old, + const TCHAR* path_new); /* Rename/Move a file or directory */ +FRESULT f_stat(const TCHAR* path, FILINFO* fno); /* Get file status */ +FRESULT f_chmod(const TCHAR* path, BYTE attr, + BYTE mask); /* Change attribute of the file/dir */ +FRESULT f_utime(const TCHAR* path, + const FILINFO* fno); /* Change times-tamp of the file/dir */ +FRESULT f_chdir(const TCHAR* path); /* Change current directory */ +FRESULT f_chdrive(const TCHAR* path); /* Change current drive */ +FRESULT f_getcwd(TCHAR* buff, UINT len); /* Get current directory */ +FRESULT f_getfree(const TCHAR* path, DWORD* nclst, + FATFS** fatfs); /* Get number of free clusters on the drive */ +FRESULT f_getlabel(const TCHAR* path, TCHAR* label, + DWORD* vsn); /* Get volume label */ +FRESULT f_setlabel(const TCHAR* label); /* Set volume label */ +FRESULT f_mount(FATFS* fs, const TCHAR* path, + BYTE opt); /* Mount/Unmount a logical drive */ +FRESULT f_mkfs(const TCHAR* path, BYTE sfd, + UINT au); /* Create a file system on the volume */ +FRESULT f_fdisk(BYTE pdrv, const DWORD szt[], + void* work); /* Divide a physical drive into some partitions */ +int f_putc(TCHAR c, FIL* fp); /* Put a character to the file */ +int f_puts(const TCHAR* str, FIL* cp); /* Put a string to the file */ +int f_printf(FIL* fp, const TCHAR* str, + ...); /* Put a formatted string to the file */ +TCHAR* f_gets(TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize)) #define f_error(fp) ((fp)->err) @@ -253,94 +267,93 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil #define EOF (-1) #endif - - - /*--------------------------------------------------------------*/ /* Additional user defined functions */ /* RTC function */ #if !_FS_READONLY && !_FS_NORTC -DWORD get_fattime (void); +DWORD get_fattime(void); #endif /* Unicode support functions */ -#if _USE_LFN /* Unicode - OEM code conversion */ -WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ -WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ -#if _USE_LFN == 3 /* Memory functions */ -void* ff_memalloc (UINT msize); /* Allocate memory block */ -void ff_memfree (void* mblock); /* Free memory block */ +#if _USE_LFN /* Unicode - OEM code conversion */ +WCHAR ff_convert(WCHAR chr, + UINT dir); /* OEM-Unicode bidirectional conversion */ +WCHAR ff_wtoupper(WCHAR chr); /* Unicode upper-case conversion */ +#if _USE_LFN == 3 /* Memory functions */ +void* ff_memalloc(UINT msize); /* Allocate memory block */ +void ff_memfree(void* mblock); /* Free memory block */ #endif #endif /* Sync functions */ #if _FS_REENTRANT -int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ -int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ -void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ -int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ +int ff_cre_syncobj(BYTE vol, _SYNC_t* sobj); /* Create a sync object */ +int ff_req_grant(_SYNC_t sobj); /* Lock sync object */ +void ff_rel_grant(_SYNC_t sobj); /* Unlock sync object */ +int ff_del_syncobj(_SYNC_t sobj); /* Delete a sync object */ #endif - - - /*--------------------------------------------------------------*/ /* Flags and offset address */ - /* File access control and file status flags (FIL.flag) */ -#define FA_READ 0x01 -#define FA_OPEN_EXISTING 0x00 +#define FA_READ 0x01 +#define FA_OPEN_EXISTING 0x00 #if !_FS_READONLY -#define FA_WRITE 0x02 -#define FA_CREATE_NEW 0x04 -#define FA_CREATE_ALWAYS 0x08 -#define FA_OPEN_ALWAYS 0x10 -#define FA__WRITTEN 0x20 -#define FA__DIRTY 0x40 +#define FA_WRITE 0x02 +#define FA_CREATE_NEW 0x04 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA__WRITTEN 0x20 +#define FA__DIRTY 0x40 #endif - /* FAT sub type (FATFS.fs_type) */ -#define FS_FAT12 1 -#define FS_FAT16 2 -#define FS_FAT32 3 - +#define FS_FAT12 1 +#define FS_FAT16 2 +#define FS_FAT32 3 /* File attribute bits for directory entry */ -#define AM_RDO 0x01 /* Read only */ -#define AM_HID 0x02 /* Hidden */ -#define AM_SYS 0x04 /* System */ -#define AM_VOL 0x08 /* Volume label */ -#define AM_LFN 0x0F /* LFN entry */ -#define AM_DIR 0x10 /* Directory */ -#define AM_ARC 0x20 /* Archive */ -#define AM_MASK 0x3F /* Mask of defined bits */ - +#define AM_RDO 0x01 /* Read only */ +#define AM_HID 0x02 /* Hidden */ +#define AM_SYS 0x04 /* System */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_DIR 0x10 /* Directory */ +#define AM_ARC 0x20 /* Archive */ +#define AM_MASK 0x3F /* Mask of defined bits */ /* Fast seek feature */ -#define CREATE_LINKMAP 0xFFFFFFFF - - +#define CREATE_LINKMAP 0xFFFFFFFF /*--------------------------------*/ /* Multi-byte word access macros */ -#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) -#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) -#else /* Use byte-by-byte access to the FAT structure */ -#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) -#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) -#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) +#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ +#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) +#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) +#define ST_WORD(ptr, val) *(WORD*)(BYTE*)(ptr) = (WORD)(val) +#define ST_DWORD(ptr, val) *(DWORD*)(BYTE*)(ptr) = (DWORD)(val) +#else /* Use byte-by-byte access to the FAT structure */ +#define LD_WORD(ptr) \ + (WORD)(((WORD) * ((BYTE*)(ptr) + 1) << 8) | (WORD) * (BYTE*)(ptr)) +#define LD_DWORD(ptr) \ + (DWORD)(((DWORD) * ((BYTE*)(ptr) + 3) << 24) | \ + ((DWORD) * ((BYTE*)(ptr) + 2) << 16) | \ + ((WORD) * ((BYTE*)(ptr) + 1) << 8) | *(BYTE*)(ptr)) +#define ST_WORD(ptr, val) \ + *(BYTE*)(ptr) = (BYTE)(val); \ + *((BYTE*)(ptr) + 1) = (BYTE)((WORD)(val) >> 8) +#define ST_DWORD(ptr, val) \ + *(BYTE*)(ptr) = (BYTE)(val); \ + *((BYTE*)(ptr) + 1) = (BYTE)((WORD)(val) >> 8); \ + *((BYTE*)(ptr) + 2) = (BYTE)((DWORD)(val) >> 16); \ + *((BYTE*)(ptr) + 3) = (BYTE)((DWORD)(val) >> 24) #endif #ifdef __cplusplus diff --git a/source/fatfs/ffconf.h b/source/fatfs/ffconf.h index fb73a5c..ce04bca 100644 --- a/source/fatfs/ffconf.h +++ b/source/fatfs/ffconf.h @@ -2,28 +2,26 @@ / FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 /---------------------------------------------------------------------------*/ -#define _FFCONF 32020 /* Revision ID */ +#define _FFCONF 32020 /* Revision ID */ /*---------------------------------------------------------------------------/ / Functions and Buffer Configurations /---------------------------------------------------------------------------*/ -#define _FS_TINY 0 +#define _FS_TINY 0 /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) / At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS / bytes. Instead of private sector buffer eliminated from the file object, / common sector buffer in the file system object (FATFS) is used for the file / data transfer. */ - -#define _FS_READONLY 0 +#define _FS_READONLY 0 /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / and optional writing functions as well. */ - -#define _FS_MINIMIZE 0 +#define _FS_MINIMIZE 0 /* This option defines minimization level to remove some basic API functions. / / 0: All basic functions are enabled. @@ -32,8 +30,7 @@ / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ - -#define _USE_STRFUNC 0 +#define _USE_STRFUNC 0 /* This option switches string functions, f_gets(), f_putc(), f_puts() and / f_printf(). / @@ -41,35 +38,29 @@ / 1: Enable without LF-CRLF conversion. / 2: Enable with LF-CRLF conversion. */ - -#define _USE_FIND 0 +#define _USE_FIND 0 /* This option switches filtered directory read feature and related functions, / f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ - -#define _USE_MKFS 0 +#define _USE_MKFS 0 /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ - -#define _USE_FASTSEEK 0 +#define _USE_FASTSEEK 0 /* This option switches fast seek feature. (0:Disable or 1:Enable) */ - -#define _USE_LABEL 0 +#define _USE_LABEL 0 /* This option switches volume label functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ - -#define _USE_FORWARD 0 +#define _USE_FORWARD 0 /* This option switches f_forward() function. (0:Disable or 1:Enable) / To enable it, also _FS_TINY need to be set to 1. */ - /*---------------------------------------------------------------------------/ / Locale and Namespace Configurations /---------------------------------------------------------------------------*/ -#define _CODE_PAGE 437 +#define _CODE_PAGE 437 /* This option specifies the OEM code page to be used on the target system. / Incorrect setting of the code page can cause a file open failure. / @@ -92,9 +83,8 @@ / 950 - Traditional Chinese Big5 (DBCS) */ - -#define _USE_LFN 2 -#define _MAX_LFN 255 +#define _USE_LFN 2 +#define _MAX_LFN 255 /* The _USE_LFN option switches the LFN feature. / / 0: Disable LFN feature. _MAX_LFN has no effect. @@ -102,22 +92,26 @@ / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / -/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must -/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. -/ When use stack for the working buffer, take care on stack overflow. When use heap +/ When enable the LFN feature, Unicode handling functions (option/unicode.c) +must +/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 +bytes. +/ When use stack for the working buffer, take care on stack overflow. When use +heap / memory for the working buffer, memory management functions, ff_memalloc() and / ff_memfree(), must be added to the project. */ - -#define _LFN_UNICODE 0 +#define _LFN_UNICODE 0 /* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) -/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE +/ To use Unicode string for the path name, enable LFN feature and set +_LFN_UNICODE / to 1. This option also affects behavior of string I/O functions. */ - -#define _STRF_ENCODE 0 -/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to -/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). +#define _STRF_ENCODE 0 +/* When _LFN_UNICODE is 1, this option selects the character encoding on the +file to +/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and +f_printf(). / / 0: ANSI/OEM / 1: UTF-16LE @@ -126,59 +120,62 @@ / / When _LFN_UNICODE is 0, this option has no effect. */ - -#define _FS_RPATH 1 +#define _FS_RPATH 1 /* This option configures relative path feature. / / 0: Disable relative path feature and remove related functions. / 1: Enable relative path feature. f_chdir() and f_chdrive() are available. / 2: f_getcwd() function is available in addition to 1. / -/ Note that directory items read via f_readdir() are affected by this option. */ - +/ Note that directory items read via f_readdir() are affected by this option. +*/ /*---------------------------------------------------------------------------/ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define _VOLUMES 1 +#define _VOLUMES 1 /* Number of volumes (logical drives) to be used. */ - -#define _STR_VOLUME_ID 0 -#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +#define _STR_VOLUME_ID 0 +#define _VOLUME_STRS "RAM", "NAND", "CF", "SD1", "SD2", "USB1", "USB2", "USB3" /* _STR_VOLUME_ID option switches string volume ID feature. -/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive +/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as +drive / number in the path name. _VOLUME_STRS defines the drive ID strings for each -/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for +/ logical drives. Number of items must be equal to _VOLUMES. Valid characters +for / the drive ID strings are: A-Z and 0-9. */ - -#define _MULTI_PARTITION 0 -/* This option switches multi-partition feature. By default (0), each logical drive -/ number is bound to the same physical drive number and only an FAT volume found on -/ the physical drive will be mounted. When multi-partition feature is enabled (1), +#define _MULTI_PARTITION 0 +/* This option switches multi-partition feature. By default (0), each logical +drive +/ number is bound to the same physical drive number and only an FAT volume +found on +/ the physical drive will be mounted. When multi-partition feature is enabled +(1), / each logical drive number is bound to arbitrary physical drive and partition / listed in the VolToPart[]. Also f_fdisk() funciton will be available. */ - -#define _MIN_SS 512 -#define _MAX_SS 512 +#define _MIN_SS 512 +#define _MAX_SS 512 /* These options configure the range of sector size to be supported. (512, 1024, -/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and -/ harddisk. But a larger value may be required for on-board flash memory and some -/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured -/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the +/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards +and +/ harddisk. But a larger value may be required for on-board flash memory and +some +/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is +configured +/ to variable sector size and GET_SECTOR_SIZE command must be implemented to +the / disk_ioctl() function. */ - -#define _USE_TRIM 0 +#define _USE_TRIM 0 /* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) / To enable Trim feature, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ - -#define _FS_NOFSINFO 0 +#define _FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this / option, and f_getfree() function at first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. @@ -189,41 +186,45 @@ / bit1=1: Do not trust last allocated cluster number in the FSINFO. */ - - /*---------------------------------------------------------------------------/ / System Configurations /---------------------------------------------------------------------------*/ -#define _FS_NORTC 1 -#define _NORTC_MON 2 -#define _NORTC_MDAY 1 -#define _NORTC_YEAR 2015 +#define _FS_NORTC 1 +#define _NORTC_MON 2 +#define _NORTC_MDAY 1 +#define _NORTC_YEAR 2015 /* The _FS_NORTC option switches timestamp feature. If the system does not have -/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable -/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp +/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to +disable +/ the timestamp feature. All objects modified by FatFs will have a fixed +timestamp / defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. -/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need +/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function +need / to be added to the project to read current time form RTC. _NORTC_MON, / _NORTC_MDAY and _NORTC_YEAR have no effect. -/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ - +/ These options have no effect at read-only configuration (_FS_READONLY == 1). +*/ -#define _FS_LOCK 0 -/* The _FS_LOCK option switches file lock feature to control duplicated file open -/ and illegal operation to open objects. This option must be 0 when _FS_READONLY +#define _FS_LOCK 0 +/* The _FS_LOCK option switches file lock feature to control duplicated file +open +/ and illegal operation to open objects. This option must be 0 when +_FS_READONLY / is 1. / -/ 0: Disable file lock feature. To avoid volume corruption, application program +/ 0: Disable file lock feature. To avoid volume corruption, application +program / should avoid illegal open, remove and rename to the open objects. -/ >0: Enable file lock feature. The value defines how many files/sub-directories +/ >0: Enable file lock feature. The value defines how many +files/sub-directories / can be opened simultaneously under file lock control. Note that the file / lock feature is independent of re-entrancy. */ - -#define _FS_REENTRANT 0 -#define _FS_TIMEOUT 1000 -#define _SYNC_t HANDLE +#define _FS_REENTRANT 0 +#define _FS_TIMEOUT 1000 +#define _SYNC_t HANDLE /* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() @@ -237,17 +238,18 @@ / option/syscall.c. / / The _FS_TIMEOUT defines timeout period in unit of time tick. -/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, +OS_EVENT*, / SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be / included somewhere in the scope of ff.c. */ - -#define _WORD_ACCESS 0 +#define _WORD_ACCESS 0 /* The _WORD_ACCESS option is an only platform dependent option. It defines / which access method is used to the word data on the FAT volume. / / 0: Byte-by-byte access. Always compatible with all platforms. -/ 1: Word access. Do not choose this unless under both the following conditions. +/ 1: Word access. Do not choose this unless under both the following +conditions. / / * Address misaligned memory access is always allowed to ALL instructions. / * Byte order on the memory is little-endian. @@ -268,4 +270,3 @@ / *2:Unaligned memory access is not supported. / *3:Some compilers generate LDM/STM for mem_cpy function. */ - diff --git a/source/fatfs/integer.h b/source/fatfs/integer.h index f254b2a..1bfa223 100644 --- a/source/fatfs/integer.h +++ b/source/fatfs/integer.h @@ -5,28 +5,28 @@ #ifndef _FF_INTEGER #define _FF_INTEGER -#ifdef _WIN32 /* FatFs development platform */ +#ifdef _WIN32 /* FatFs development platform */ #include #include -#else /* Embedded platform */ +#else /* Embedded platform */ /* This type MUST be 8 bit */ -typedef unsigned char BYTE; +typedef unsigned char BYTE; /* These types MUST be 16 bit */ -typedef short SHORT; -typedef unsigned short WORD; -typedef unsigned short WCHAR; +typedef short SHORT; +typedef unsigned short WORD; +typedef unsigned short WCHAR; /* These types MUST be 16 bit or 32 bit */ -typedef int INT; -typedef unsigned int UINT; +typedef int INT; +typedef unsigned int UINT; /* These types MUST be 32 bit */ -typedef long LONG; -typedef unsigned long DWORD; +typedef long LONG; +typedef unsigned long DWORD; #endif diff --git a/source/fatfs/sdmmc.c b/source/fatfs/sdmmc.c index dbf353e..79d5cbe 100644 --- a/source/fatfs/sdmmc.c +++ b/source/fatfs/sdmmc.c @@ -35,8 +35,8 @@ #include "sdmmc.h" //#include "DrawCharacter.h" -//Uncomment to enable 32bit fifo support? -//not currently working +// Uncomment to enable 32bit fifo support? +// not currently working //#define DATA32_SUPPORT #define TRUE 1 @@ -44,14 +44,14 @@ #define bool int -#define NO_INLINE __attribute__ ((noinline)) +#define NO_INLINE __attribute__((noinline)) -#define RGB(r,g,b) (r<<24|b<<16|g<<8|r) +#define RGB(r, g, b) (r << 24 | b << 16 | g << 8 | r) #ifdef __cplusplus extern "C" { #endif - void waitcycles(uint32_t val); +void waitcycles(uint32_t val); #ifdef __cplusplus }; #endif @@ -59,610 +59,658 @@ extern "C" { //#define DEBUG_SDMMC #ifdef DEBUG_SDMMC - extern uint8_t* topScreen; - extern void DrawHexWithName(unsigned char *screen, const char *str, unsigned int hex, int x, int y, int color, int bgcolor); - #define DEBUGPRINT(scr,str,hex,x,y,color,bg) DrawHexWithName(scr,str,hex,x,y,color,bg) +extern uint8_t* topScreen; +extern void DrawHexWithName(unsigned char* screen, const char* str, + unsigned int hex, int x, int y, int color, + int bgcolor); +#define DEBUGPRINT(scr, str, hex, x, y, color, bg) \ + DrawHexWithName(scr, str, hex, x, y, color, bg) #else - #define DEBUGPRINT(...) +#define DEBUGPRINT(...) #endif -//extern "C" void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args); -//extern "C" void inittarget(struct mmcdevice *ctx); -//extern "C" int SD_Init(); -//extern "C" int SD_Init2(); -//extern "C" int Nand_Init2(); -//extern "C" void InitSD(); +// extern "C" void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, +// uint32_t args); +// extern "C" void inittarget(struct mmcdevice *ctx); +// extern "C" int SD_Init(); +// extern "C" int SD_Init2(); +// extern "C" int Nand_Init2(); +// extern "C" void InitSD(); struct mmcdevice handelNAND; struct mmcdevice handelSD; -mmcdevice *getMMCDevice(int drive) +mmcdevice* +getMMCDevice(int drive) { - if(drive==0) return &handelNAND; - return &handelSD; + if (drive == 0) + return &handelNAND; + return &handelSD; } -int geterror(struct mmcdevice *ctx) +int +geterror(struct mmcdevice* ctx) { - return (ctx->error << 29) >> 31; + return (ctx->error << 29) >> 31; } - -void inittarget(struct mmcdevice *ctx) +void +inittarget(struct mmcdevice* ctx) { - sdmmc_mask16(REG_SDPORTSEL,0x3,(uint16_t)ctx->devicenumber); - setckl(ctx->clk); - if(ctx->SDOPT == 0) - { - sdmmc_mask16(REG_SDOPT,0,0x8000); - } - else - { - sdmmc_mask16(REG_SDOPT,0x8000,0); - } - + sdmmc_mask16(REG_SDPORTSEL, 0x3, (uint16_t)ctx->devicenumber); + setckl(ctx->clk); + if (ctx->SDOPT == 0) { + sdmmc_mask16(REG_SDOPT, 0, 0x8000); + } else { + sdmmc_mask16(REG_SDOPT, 0x8000, 0); + } } - -void NO_INLINE sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args) +void NO_INLINE +sdmmc_send_command(struct mmcdevice* ctx, uint32_t cmd, uint32_t args) { - bool getSDRESP = (cmd << 15) >> 31; - uint16_t flags = (cmd << 15) >> 31; - const bool readdata = cmd & 0x20000; - const bool writedata = cmd & 0x40000; - - if(readdata || writedata) - { - flags |= TMIO_STAT0_DATAEND; - } - - ctx->error = 0; - while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working? - sdmmc_write16(REG_SDIRMASK0,0); - sdmmc_write16(REG_SDIRMASK1,0); - sdmmc_write16(REG_SDSTATUS0,0); - sdmmc_write16(REG_SDSTATUS1,0); + bool getSDRESP = (cmd << 15) >> 31; + uint16_t flags = (cmd << 15) >> 31; + const bool readdata = cmd & 0x20000; + const bool writedata = cmd & 0x40000; + + if (readdata || writedata) { + flags |= TMIO_STAT0_DATAEND; + } + + ctx->error = 0; + while ((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)) + ; // mmc working? + sdmmc_write16(REG_SDIRMASK0, 0); + sdmmc_write16(REG_SDIRMASK1, 0); + sdmmc_write16(REG_SDSTATUS0, 0); + sdmmc_write16(REG_SDSTATUS1, 0); #ifdef DATA32_SUPPORT // if(readdata)sdmmc_mask16(REG_DATACTL32, 0x1000, 0x800); // if(writedata)sdmmc_mask16(REG_DATACTL32, 0x800, 0x1000); // sdmmc_mask16(REG_DATACTL32,0x1800,2); #else - sdmmc_mask16(REG_DATACTL32,0x1800,0); + sdmmc_mask16(REG_DATACTL32, 0x1800, 0); #endif - sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); - sdmmc_write16(REG_SDCMDARG1,args >> 16); - sdmmc_write16(REG_SDCMD,cmd &0xFFFF); - - uint32_t size = ctx->size; - uint16_t *dataPtr = (uint16_t*)ctx->data; + sdmmc_write16(REG_SDCMDARG0, args & 0xFFFF); + sdmmc_write16(REG_SDCMDARG1, args >> 16); + sdmmc_write16(REG_SDCMD, cmd & 0xFFFF); + + uint32_t size = ctx->size; + uint16_t* dataPtr = (uint16_t*)ctx->data; #ifdef DATA32_SUPPORT - uint32_t *dataPtr32 = (uint32_t*)ctx->data; + uint32_t* dataPtr32 = (uint32_t*)ctx->data; #endif - - bool useBuf = ( NULL != dataPtr ); + + bool useBuf = (NULL != dataPtr); #ifdef DATA32_SUPPORT - bool useBuf32 = (useBuf && (0 == (3 & ((uint32_t)dataPtr)))); + bool useBuf32 = (useBuf && (0 == (3 & ((uint32_t)dataPtr)))); #endif - - uint16_t status0 = 0; - while(1) - { - volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1); + + uint16_t status0 = 0; + while (1) { + volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1); #ifdef DATA32_SUPPORT - volatile uint16_t ctl32 = sdmmc_read16(REG_DATACTL32); - if((ctl32 & 0x100)) + volatile uint16_t ctl32 = sdmmc_read16(REG_DATACTL32); + if ((ctl32 & 0x100)) #else - if((status1 & TMIO_STAT1_RXRDY)) + if ((status1 & TMIO_STAT1_RXRDY)) #endif - { - if(readdata) - { - if(useBuf) - { - sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); - //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY); - if(size > 0x1FF) - { - #ifdef DATA32_SUPPORT - if(useBuf32) - { - for(int i = 0; i<0x200; i+=4) - { - *dataPtr32++ = sdmmc_read32(REG_SDFIFO32); - } - } - else - { - #endif - for(int i = 0; i<0x200; i+=2) - { - *dataPtr++ = sdmmc_read16(REG_SDFIFO); - } - #ifdef DATA32_SUPPORT - } - #endif - size -= 0x200; - } - } - - sdmmc_mask16(REG_DATACTL32, 0x800, 0); - } - } + { + if (readdata) { + if (useBuf) { + sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); + // sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY); + if (size > 0x1FF) { #ifdef DATA32_SUPPORT - if(!(ctl32 & 0x200)) + if (useBuf32) { + for (int i = 0; i < 0x200; i += 4) { + *dataPtr32++ = sdmmc_read32(REG_SDFIFO32); + } + } else { +#endif + for (int i = 0; i < 0x200; i += 2) { + *dataPtr++ = sdmmc_read16(REG_SDFIFO); + } +#ifdef DATA32_SUPPORT + } +#endif + size -= 0x200; + } + } + + sdmmc_mask16(REG_DATACTL32, 0x800, 0); + } + } +#ifdef DATA32_SUPPORT + if (!(ctl32 & 0x200)) #else - if((status1 & TMIO_STAT1_TXRQ)) + if ((status1 & TMIO_STAT1_TXRQ)) #endif - { - if(writedata) - { - if(useBuf) - { - sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); - //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ); - if(size > 0x1FF) - { - #ifdef DATA32_SUPPORT - for(int i = 0; i<0x200; i+=4) - { - sdmmc_write32(REG_SDFIFO32,*dataPtr32++); - } - #else - for(int i = 0; i<0x200; i+=2) - { - sdmmc_write16(REG_SDFIFO,*dataPtr++); - } - #endif - size -= 0x200; - } - } - - sdmmc_mask16(REG_DATACTL32, 0x1000, 0); - } - } - if(status1 & TMIO_MASK_GW) - { - ctx->error |= 4; - break; - } - - if(!(status1 & TMIO_STAT1_CMD_BUSY)) - { - status0 = sdmmc_read16(REG_SDSTATUS0); - if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) - { - ctx->error |= 0x1; - } - if(status0 & TMIO_STAT0_DATAEND) - { - ctx->error |= 0x2; - } - - if((status0 & flags) == flags) - break; - } - } - ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); - ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); - sdmmc_write16(REG_SDSTATUS0,0); - sdmmc_write16(REG_SDSTATUS1,0); - - if(getSDRESP != 0) - { - ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16); - ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16); - ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16); - ctx->ret[3] = sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16); - } + { + if (writedata) { + if (useBuf) { + sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); + // sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ); + if (size > 0x1FF) { +#ifdef DATA32_SUPPORT + for (int i = 0; i < 0x200; i += 4) { + sdmmc_write32(REG_SDFIFO32, *dataPtr32++); + } +#else + for (int i = 0; i < 0x200; i += 2) { + sdmmc_write16(REG_SDFIFO, *dataPtr++); + } +#endif + size -= 0x200; + } + } + + sdmmc_mask16(REG_DATACTL32, 0x1000, 0); + } + } + if (status1 & TMIO_MASK_GW) { + ctx->error |= 4; + break; + } + + if (!(status1 & TMIO_STAT1_CMD_BUSY)) { + status0 = sdmmc_read16(REG_SDSTATUS0); + if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) { + ctx->error |= 0x1; + } + if (status0 & TMIO_STAT0_DATAEND) { + ctx->error |= 0x2; + } + + if ((status0 & flags) == flags) + break; + } + } + ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); + ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); + sdmmc_write16(REG_SDSTATUS0, 0); + sdmmc_write16(REG_SDSTATUS1, 0); + + if (getSDRESP != 0) { + ctx->ret[0] = + sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16); + ctx->ret[1] = + sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16); + ctx->ret[2] = + sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16); + ctx->ret[3] = + sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16); + } } -int NO_INLINE sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in) +int NO_INLINE +sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t* in) { - if(handelSD.isSDHC == 0) sector_no <<= 9; - inittarget(&handelSD); - sdmmc_write16(REG_SDSTOP,0x100); + if (handelSD.isSDHC == 0) + sector_no <<= 9; + inittarget(&handelSD); + sdmmc_write16(REG_SDSTOP, 0x100); #ifdef DATA32_SUPPORT - sdmmc_write16(REG_SDBLKCOUNT32,numsectors); - sdmmc_write16(REG_SDBLKLEN32,0x200); + sdmmc_write16(REG_SDBLKCOUNT32, numsectors); + sdmmc_write16(REG_SDBLKLEN32, 0x200); #endif - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handelSD.data = in; - handelSD.size = numsectors << 9; - sdmmc_send_command(&handelSD,0x52C19,sector_no); - return geterror(&handelSD); + sdmmc_write16(REG_SDBLKCOUNT, numsectors); + handelSD.data = in; + handelSD.size = numsectors << 9; + sdmmc_send_command(&handelSD, 0x52C19, sector_no); + return geterror(&handelSD); } -int NO_INLINE sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) +int NO_INLINE +sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t* out) { - if(handelSD.isSDHC == 0) sector_no <<= 9; - inittarget(&handelSD); - sdmmc_write16(REG_SDSTOP,0x100); + if (handelSD.isSDHC == 0) + sector_no <<= 9; + inittarget(&handelSD); + sdmmc_write16(REG_SDSTOP, 0x100); #ifdef DATA32_SUPPORT - sdmmc_write16(REG_SDBLKCOUNT32,numsectors); - sdmmc_write16(REG_SDBLKLEN32,0x200); + sdmmc_write16(REG_SDBLKCOUNT32, numsectors); + sdmmc_write16(REG_SDBLKLEN32, 0x200); #endif - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handelSD.data = out; - handelSD.size = numsectors << 9; - sdmmc_send_command(&handelSD,0x33C12,sector_no); - return geterror(&handelSD); + sdmmc_write16(REG_SDBLKCOUNT, numsectors); + handelSD.data = out; + handelSD.size = numsectors << 9; + sdmmc_send_command(&handelSD, 0x33C12, sector_no); + return geterror(&handelSD); } - - -int NO_INLINE sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) +int NO_INLINE +sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t* out) { - if(handelNAND.isSDHC == 0) sector_no <<= 9; - inittarget(&handelNAND); - sdmmc_write16(REG_SDSTOP,0x100); + if (handelNAND.isSDHC == 0) + sector_no <<= 9; + inittarget(&handelNAND); + sdmmc_write16(REG_SDSTOP, 0x100); #ifdef DATA32_SUPPORT - sdmmc_write16(REG_SDBLKCOUNT32,numsectors); - sdmmc_write16(REG_SDBLKLEN32,0x200); + sdmmc_write16(REG_SDBLKCOUNT32, numsectors); + sdmmc_write16(REG_SDBLKLEN32, 0x200); #endif - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handelNAND.data = out; - handelNAND.size = numsectors << 9; - sdmmc_send_command(&handelNAND,0x33C12,sector_no); - inittarget(&handelSD); - return geterror(&handelNAND); + sdmmc_write16(REG_SDBLKCOUNT, numsectors); + handelNAND.data = out; + handelNAND.size = numsectors << 9; + sdmmc_send_command(&handelNAND, 0x33C12, sector_no); + inittarget(&handelSD); + return geterror(&handelNAND); } -int NO_INLINE sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in) //experimental +int NO_INLINE sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, + uint8_t* in) // experimental { - if(handelNAND.isSDHC == 0) sector_no <<= 9; - inittarget(&handelNAND); - sdmmc_write16(REG_SDSTOP,0x100); + if (handelNAND.isSDHC == 0) + sector_no <<= 9; + inittarget(&handelNAND); + sdmmc_write16(REG_SDSTOP, 0x100); #ifdef DATA32_SUPPORT - sdmmc_write16(REG_SDBLKCOUNT32,numsectors); - sdmmc_write16(REG_SDBLKLEN32,0x200); + sdmmc_write16(REG_SDBLKCOUNT32, numsectors); + sdmmc_write16(REG_SDBLKLEN32, 0x200); #endif - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handelNAND.data = in; - handelNAND.size = numsectors << 9; - sdmmc_send_command(&handelNAND,0x52C19,sector_no); - inittarget(&handelSD); - return geterror(&handelNAND); + sdmmc_write16(REG_SDBLKCOUNT, numsectors); + handelNAND.data = in; + handelNAND.size = numsectors << 9; + sdmmc_send_command(&handelNAND, 0x52C19, sector_no); + inittarget(&handelSD); + return geterror(&handelNAND); } -static uint32_t calcSDSize(uint8_t* csd, int type) +static uint32_t +calcSDSize(uint8_t* csd, int type) { - uint32_t result=0; - if(type == -1) type = csd[14] >> 6; - switch(type) - { - case 0: - { - uint32_t block_len=csd[9]&0xf; - block_len=1<>7)|((csd[5]&3)<<1); - mult=1<<(mult+2); - result=csd[8]&3; - result=(result<<8)|csd[7]; - result=(result<<2)|(csd[6]>>6); - result=(result+1)*mult*block_len/512; - } - break; - case 1: - result=csd[7]&0x3f; - result=(result<<8)|csd[6]; - result=(result<<8)|csd[5]; - result=(result+1)*1024; - break; - } - return result; + uint32_t result = 0; + if (type == -1) + type = csd[14] >> 6; + switch (type) { + case 0: { + uint32_t block_len = csd[9] & 0xf; + block_len = 1 << block_len; + uint32_t mult = (csd[4] >> 7) | ((csd[5] & 3) << 1); + mult = 1 << (mult + 2); + result = csd[8] & 3; + result = (result << 8) | csd[7]; + result = (result << 2) | (csd[6] >> 6); + result = (result + 1) * mult * block_len / 512; + } break; + case 1: + result = csd[7] & 0x3f; + result = (result << 8) | csd[6]; + result = (result << 8) | csd[5]; + result = (result + 1) * 1024; + break; + } + return result; } -void InitSD() +void +InitSD() { - //NAND - handelNAND.isSDHC = 0; - handelNAND.SDOPT = 0; - handelNAND.res = 0; - handelNAND.initarg = 1; - handelNAND.clk = 0x80; - handelNAND.devicenumber = 1; - - //SD - handelSD.isSDHC = 0; - handelSD.SDOPT = 0; - handelSD.res = 0; - handelSD.initarg = 0; - handelSD.clk = 0x80; - handelSD.devicenumber = 0; - - //sdmmc_mask16(0x100,0x800,0); - //sdmmc_mask16(0x100,0x1000,0); - //sdmmc_mask16(0x100,0x0,0x402); - //sdmmc_mask16(0xD8,0x22,0x2); - //sdmmc_mask16(0x100,0x2,0); - //sdmmc_mask16(0xD8,0x22,0); - //sdmmc_write16(0x104,0); - //sdmmc_write16(0x108,1); - //sdmmc_mask16(REG_SDRESET,1,0); //not in new Version -- nintendo's code does this - //sdmmc_mask16(REG_SDRESET,0,1); //not in new Version -- nintendo's code does this - //sdmmc_mask16(0x20,0,0x31D); - //sdmmc_mask16(0x22,0,0x837F); - //sdmmc_mask16(0xFC,0,0xDB); - //sdmmc_mask16(0xFE,0,0xDB); - ////sdmmc_write16(REG_SDCLKCTL,0x20); - ////sdmmc_write16(REG_SDOPT,0x40EE); - ////sdmmc_mask16(0x02,0x3,0); - //sdmmc_write16(REG_SDCLKCTL,0x40); - //sdmmc_write16(REG_SDOPT,0x40EB); - //sdmmc_mask16(0x02,0x3,0); - //sdmmc_write16(REG_SDBLKLEN,0x200); - //sdmmc_write16(REG_SDSTOP,0); - - *(volatile uint16_t*)0x10006100 &= 0xF7FFu; //SDDATACTL32 - *(volatile uint16_t*)0x10006100 &= 0xEFFFu; //SDDATACTL32 + // NAND + handelNAND.isSDHC = 0; + handelNAND.SDOPT = 0; + handelNAND.res = 0; + handelNAND.initarg = 1; + handelNAND.clk = 0x80; + handelNAND.devicenumber = 1; + + // SD + handelSD.isSDHC = 0; + handelSD.SDOPT = 0; + handelSD.res = 0; + handelSD.initarg = 0; + handelSD.clk = 0x80; + handelSD.devicenumber = 0; + + // sdmmc_mask16(0x100,0x800,0); + // sdmmc_mask16(0x100,0x1000,0); + // sdmmc_mask16(0x100,0x0,0x402); + // sdmmc_mask16(0xD8,0x22,0x2); + // sdmmc_mask16(0x100,0x2,0); + // sdmmc_mask16(0xD8,0x22,0); + // sdmmc_write16(0x104,0); + // sdmmc_write16(0x108,1); + // sdmmc_mask16(REG_SDRESET,1,0); //not in new Version -- nintendo's code + // does this + // sdmmc_mask16(REG_SDRESET,0,1); //not in new Version -- nintendo's code + // does this + // sdmmc_mask16(0x20,0,0x31D); + // sdmmc_mask16(0x22,0,0x837F); + // sdmmc_mask16(0xFC,0,0xDB); + // sdmmc_mask16(0xFE,0,0xDB); + ////sdmmc_write16(REG_SDCLKCTL,0x20); + ////sdmmc_write16(REG_SDOPT,0x40EE); + ////sdmmc_mask16(0x02,0x3,0); + // sdmmc_write16(REG_SDCLKCTL,0x40); + // sdmmc_write16(REG_SDOPT,0x40EB); + // sdmmc_mask16(0x02,0x3,0); + // sdmmc_write16(REG_SDBLKLEN,0x200); + // sdmmc_write16(REG_SDSTOP,0); + + *(volatile uint16_t*)0x10006100 &= 0xF7FFu; // SDDATACTL32 + *(volatile uint16_t*)0x10006100 &= 0xEFFFu; // SDDATACTL32 #ifdef DATA32_SUPPORT - *(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32 + *(volatile uint16_t*)0x10006100 |= 0x402u; // SDDATACTL32 #else - *(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32 + *(volatile uint16_t*)0x10006100 |= 0x402u; // SDDATACTL32 #endif - *(volatile uint16_t*)0x100060D8 = (*(volatile uint16_t*)0x100060D8 & 0xFFDD) | 2; + *(volatile uint16_t*)0x100060D8 = + (*(volatile uint16_t*)0x100060D8 & 0xFFDD) | 2; #ifdef DATA32_SUPPORT - *(volatile uint16_t*)0x10006100 &= 0xFFFFu; //SDDATACTL32 - *(volatile uint16_t*)0x100060D8 &= 0xFFDFu; //SDDATACTL - *(volatile uint16_t*)0x10006104 = 512; //SDBLKLEN32 + *(volatile uint16_t*)0x10006100 &= 0xFFFFu; // SDDATACTL32 + *(volatile uint16_t*)0x100060D8 &= 0xFFDFu; // SDDATACTL + *(volatile uint16_t*)0x10006104 = 512; // SDBLKLEN32 #else - *(volatile uint16_t*)0x10006100 &= 0xFFFDu; //SDDATACTL32 - *(volatile uint16_t*)0x100060D8 &= 0xFFDDu; //SDDATACTL - *(volatile uint16_t*)0x10006104 = 0; //SDBLKLEN32 + *(volatile uint16_t*)0x10006100 &= 0xFFFDu; // SDDATACTL32 + *(volatile uint16_t*)0x100060D8 &= 0xFFDDu; // SDDATACTL + *(volatile uint16_t*)0x10006104 = 0; // SDBLKLEN32 #endif - *(volatile uint16_t*)0x10006108 = 1; //SDBLKCOUNT32 - *(volatile uint16_t*)0x100060E0 &= 0xFFFEu; //SDRESET - *(volatile uint16_t*)0x100060E0 |= 1u; //SDRESET - *(volatile uint16_t*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0 - *(volatile uint16_t*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1 - *(volatile uint16_t*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7 - *(volatile uint16_t*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8 - *(volatile uint16_t*)0x10006002 &= 0xFFFCu; //SDPORTSEL + *(volatile uint16_t*)0x10006108 = 1; // SDBLKCOUNT32 + *(volatile uint16_t*)0x100060E0 &= 0xFFFEu; // SDRESET + *(volatile uint16_t*)0x100060E0 |= 1u; // SDRESET + *(volatile uint16_t*)0x10006020 |= TMIO_MASK_ALL; // SDIR_MASK0 + *(volatile uint16_t*)0x10006022 |= TMIO_MASK_ALL >> 16; // SDIR_MASK1 + *(volatile uint16_t*)0x100060FC |= 0xDBu; // SDCTL_RESERVED7 + *(volatile uint16_t*)0x100060FE |= 0xDBu; // SDCTL_RESERVED8 + *(volatile uint16_t*)0x10006002 &= 0xFFFCu; // SDPORTSEL #ifdef DATA32_SUPPORT - *(volatile uint16_t*)0x10006024 = 0x20; - *(volatile uint16_t*)0x10006028 = 0x40EE; + *(volatile uint16_t*)0x10006024 = 0x20; + *(volatile uint16_t*)0x10006028 = 0x40EE; #else - *(volatile uint16_t*)0x10006024 = 0x40; //Nintendo sets this to 0x20 - *(volatile uint16_t*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE + *(volatile uint16_t*)0x10006024 = 0x40; // Nintendo sets this to 0x20 + *(volatile uint16_t*)0x10006028 = 0x40EB; // Nintendo sets this to 0x40EE #endif - *(volatile uint16_t*)0x10006002 &= 0xFFFCu; ////SDPORTSEL - *(volatile uint16_t*)0x10006026 = 512; //SDBLKLEN - *(volatile uint16_t*)0x10006008 = 0; //SDSTOP - - inittarget(&handelSD); + *(volatile uint16_t*)0x10006002 &= 0xFFFCu; ////SDPORTSEL + *(volatile uint16_t*)0x10006026 = 512; // SDBLKLEN + *(volatile uint16_t*)0x10006008 = 0; // SDSTOP + + inittarget(&handelSD); } -int Nand_Init() +int +Nand_Init() { - inittarget(&handelNAND); - waitcycles(0xF000); - - DEBUGPRINT(topScreen, "0x00000 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelNAND,0,0); - - DEBUGPRINT(topScreen, "0x10701 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - do - { - do - { - sdmmc_send_command(&handelNAND,0x10701,0x100000); - DEBUGPRINT(topScreen, "error ", handelNAND.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208)); - DEBUGPRINT(topScreen, "ret: ", handelNAND.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208)); - DEBUGPRINT(topScreen, "test ", 3, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208)); - } while ( !(handelNAND.error & 1) ); - } - while((handelNAND.ret[0] & 0x80000000) == 0); - - DEBUGPRINT(topScreen, "0x10602 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelNAND,0x10602,0x0); - if((handelNAND.error & 0x4))return -1; - - DEBUGPRINT(topScreen, "0x10403 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelNAND,0x10403,handelNAND.initarg << 0x10); - if((handelNAND.error & 0x4))return -1; - - DEBUGPRINT(topScreen, "0x10609 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelNAND,0x10609,handelNAND.initarg << 0x10); - if((handelNAND.error & 0x4))return -1; - - DEBUGPRINT(topScreen, "0x10407 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - handelNAND.total_size = calcSDSize((uint8_t*)&handelNAND.ret[0],0); - handelNAND.clk = 1; - setckl(1); - - sdmmc_send_command(&handelNAND,0x10407,handelNAND.initarg << 0x10); - if((handelNAND.error & 0x4))return -1; - - DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - handelNAND.SDOPT = 1; - - sdmmc_send_command(&handelNAND,0x10506,0x3B70100); - if((handelNAND.error & 0x4))return -1; - - DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelNAND,0x10506,0x3B90100); - if((handelNAND.error & 0x4))return -1; - - DEBUGPRINT(topScreen, "0x1040D ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelNAND,0x1040D,handelNAND.initarg << 0x10); - if((handelNAND.error & 0x4))return -1; - - DEBUGPRINT(topScreen, "0x10410 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelNAND,0x10410,0x200); - if((handelNAND.error & 0x4))return -1; - - handelNAND.clk |= 0x200; - - inittarget(&handelSD); - - return 0; + inittarget(&handelNAND); + waitcycles(0xF000); + + DEBUGPRINT(topScreen, "0x00000 ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelNAND, 0, 0); + + DEBUGPRINT(topScreen, "0x10701 ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + do { + do { + sdmmc_send_command(&handelNAND, 0x10701, 0x100000); + DEBUGPRINT(topScreen, "error ", handelNAND.error, 10, 20 + 17 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + DEBUGPRINT(topScreen, "ret: ", handelNAND.ret[0], 10, 20 + 18 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + DEBUGPRINT(topScreen, "test ", 3, 10, 20 + 19 * 8, RGB(40, 40, 40), + RGB(208, 208, 208)); + } while (!(handelNAND.error & 1)); + } while ((handelNAND.ret[0] & 0x80000000) == 0); + + DEBUGPRINT(topScreen, "0x10602 ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelNAND, 0x10602, 0x0); + if ((handelNAND.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10403 ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelNAND, 0x10403, handelNAND.initarg << 0x10); + if ((handelNAND.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10609 ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelNAND, 0x10609, handelNAND.initarg << 0x10); + if ((handelNAND.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10407 ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + handelNAND.total_size = calcSDSize((uint8_t*)&handelNAND.ret[0], 0); + handelNAND.clk = 1; + setckl(1); + + sdmmc_send_command(&handelNAND, 0x10407, handelNAND.initarg << 0x10); + if ((handelNAND.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + handelNAND.SDOPT = 1; + + sdmmc_send_command(&handelNAND, 0x10506, 0x3B70100); + if ((handelNAND.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelNAND, 0x10506, 0x3B90100); + if ((handelNAND.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x1040D ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelNAND, 0x1040D, handelNAND.initarg << 0x10); + if ((handelNAND.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10410 ", handelNAND.error, 10, 20 + 13 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelNAND, 0x10410, 0x200); + if ((handelNAND.error & 0x4)) + return -1; + + handelNAND.clk |= 0x200; + + inittarget(&handelSD); + + return 0; } -int SD_Init() +int +SD_Init() { - inittarget(&handelSD); - //waitcycles(0x3E8); - //waitcycles(0xF000); - - waitcycles(1u << 19); //Card needs a little bit of time to be detected, it seems - if (!(*((volatile uint16_t*)0x1000601c) & TMIO_STAT0_SIGSTATE)) return -1; // check if card inserted - - DEBUGPRINT(topScreen, "0x00000 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - sdmmc_send_command(&handelSD,0,0); - DEBUGPRINT(topScreen, "0x10408 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - sdmmc_send_command(&handelSD,0x10408,0x1AA); - //uint32_t temp = (handelSD.ret[0] == 0x1AA) << 0x1E; - uint32_t temp = (handelSD.error & 0x1) << 0x1E; - - DEBUGPRINT(topScreen, "0x10769 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 15*8, RGB(40, 40, 40), RGB(208, 208, 208)); - DEBUGPRINT(topScreen, "temp: ", temp, 10, 20 + 16*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - //int count = 0; - uint32_t temp2 = 0; - do - { - do - { - sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10); - sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp); - temp2 = 1; - } while ( !(handelSD.error & 1) ); - - //DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208)); - //DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208)); - //DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208)); - } - while((handelSD.ret[0] & 0x80000000) == 0); - //do - //{ - // sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10); - // sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp); - // - // DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208)); - // DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208)); - // DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208)); - //} - //while(!(handelSD.ret[0] & 0x80000000)); - - if(!((handelSD.ret[0] >> 30) & 1) || !temp) - temp2 = 0; - - handelSD.isSDHC = temp2; - //handelSD.isSDHC = (handelSD.ret[0] & 0x40000000); - - DEBUGPRINT(topScreen, "0x10602 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelSD,0x10602,0); - if((handelSD.error & 0x4)) return -1; - - DEBUGPRINT(topScreen, "0x10403 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelSD,0x10403,0); - if((handelSD.error & 0x4)) return -1; - handelSD.initarg = handelSD.ret[0] >> 0x10; - - DEBUGPRINT(topScreen, "0x10609 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelSD,0x10609,handelSD.initarg << 0x10); - if((handelSD.error & 0x4)) return -1; - - handelSD.total_size = calcSDSize((uint8_t*)&handelSD.ret[0],-1); - handelSD.clk = 1; - setckl(1); - - DEBUGPRINT(topScreen, "0x10507 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelSD,0x10507,handelSD.initarg << 0x10); - if((handelSD.error & 0x4)) return -1; - - DEBUGPRINT(topScreen, "0x10437 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10); - if((handelSD.error & 0x4)) return -1; - - DEBUGPRINT(topScreen, "0x10446 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - handelSD.SDOPT = 1; - sdmmc_send_command(&handelSD,0x10446,0x2); - if((handelSD.error & 0x4)) return -1; - - DEBUGPRINT(topScreen, "0x1040D ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelSD,0x1040D,handelSD.initarg << 0x10); - if((handelSD.error & 0x4)) return -1; - - DEBUGPRINT(topScreen, "0x10410 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208)); - - sdmmc_send_command(&handelSD,0x10410,0x200); - if((handelSD.error & 0x4)) return -1; - handelSD.clk |= 0x200; - - return 0; + inittarget(&handelSD); + // waitcycles(0x3E8); + // waitcycles(0xF000); + + waitcycles( + 1u << 19); // Card needs a little bit of time to be detected, it seems + if (!(*((volatile uint16_t*)0x1000601c) & TMIO_STAT0_SIGSTATE)) + return -1; // check if card inserted + + DEBUGPRINT(topScreen, "0x00000 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + sdmmc_send_command(&handelSD, 0, 0); + DEBUGPRINT(topScreen, "0x10408 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + sdmmc_send_command(&handelSD, 0x10408, 0x1AA); + // uint32_t temp = (handelSD.ret[0] == 0x1AA) << 0x1E; + uint32_t temp = (handelSD.error & 0x1) << 0x1E; + + DEBUGPRINT(topScreen, "0x10769 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 15 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + DEBUGPRINT(topScreen, "temp: ", temp, 10, 20 + 16 * 8, RGB(40, 40, 40), + RGB(208, 208, 208)); + + // int count = 0; + uint32_t temp2 = 0; + do { + do { + sdmmc_send_command(&handelSD, 0x10437, handelSD.initarg << 0x10); + sdmmc_send_command(&handelSD, 0x10769, 0x00FF8000 | temp); + temp2 = 1; + } while (!(handelSD.error & 1)); + + // DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, + // RGB(40, 40, 40), RGB(208, 208, 208)); + // DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, + // RGB(40, 40, 40), RGB(208, 208, 208)); + // DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, + // 40), RGB(208, 208, 208)); + } while ((handelSD.ret[0] & 0x80000000) == 0); + // do + //{ + // sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10); + // sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp); + // + // DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, + //RGB(40, 40, 40), RGB(208, 208, 208)); + // DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, + //RGB(40, 40, 40), RGB(208, 208, 208)); + // DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, + //40), RGB(208, 208, 208)); + //} + // while(!(handelSD.ret[0] & 0x80000000)); + + if (!((handelSD.ret[0] >> 30) & 1) || !temp) + temp2 = 0; + + handelSD.isSDHC = temp2; + // handelSD.isSDHC = (handelSD.ret[0] & 0x40000000); + + DEBUGPRINT(topScreen, "0x10602 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelSD, 0x10602, 0); + if ((handelSD.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10403 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelSD, 0x10403, 0); + if ((handelSD.error & 0x4)) + return -1; + handelSD.initarg = handelSD.ret[0] >> 0x10; + + DEBUGPRINT(topScreen, "0x10609 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelSD, 0x10609, handelSD.initarg << 0x10); + if ((handelSD.error & 0x4)) + return -1; + + handelSD.total_size = calcSDSize((uint8_t*)&handelSD.ret[0], -1); + handelSD.clk = 1; + setckl(1); + + DEBUGPRINT(topScreen, "0x10507 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelSD, 0x10507, handelSD.initarg << 0x10); + if ((handelSD.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10437 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelSD, 0x10437, handelSD.initarg << 0x10); + if ((handelSD.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10446 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + handelSD.SDOPT = 1; + sdmmc_send_command(&handelSD, 0x10446, 0x2); + if ((handelSD.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x1040D ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelSD, 0x1040D, handelSD.initarg << 0x10); + if ((handelSD.error & 0x4)) + return -1; + + DEBUGPRINT(topScreen, "0x10410 ", handelSD.error, 10, 20 + 14 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + + sdmmc_send_command(&handelSD, 0x10410, 0x200); + if ((handelSD.error & 0x4)) + return -1; + handelSD.clk |= 0x200; + + return 0; } -int sdmmc_sdcard_init() +int +sdmmc_sdcard_init() { - DEBUGPRINT(topScreen, "sdmmc_sdcard_init ", handelSD.error, 10, 20 + 2*8, RGB(40, 40, 40), RGB(208, 208, 208)); - InitSD(); - //SD_Init2(); - //Nand_Init(); - Nand_Init(); - DEBUGPRINT(topScreen, "nand_res ", nand_res, 10, 20 + 3*8, RGB(40, 40, 40), RGB(208, 208, 208)); - if (SD_Init() != 0) return FALSE; - DEBUGPRINT(topScreen, "sd_res ", sd_res, 10, 20 + 4*8, RGB(40, 40, 40), RGB(208, 208, 208)); - + DEBUGPRINT(topScreen, "sdmmc_sdcard_init ", handelSD.error, 10, 20 + 2 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + InitSD(); + // SD_Init2(); + // Nand_Init(); + Nand_Init(); + DEBUGPRINT(topScreen, "nand_res ", nand_res, 10, 20 + 3 * 8, + RGB(40, 40, 40), RGB(208, 208, 208)); + if (SD_Init() != 0) + return FALSE; + DEBUGPRINT(topScreen, "sd_res ", sd_res, 10, 20 + 4 * 8, RGB(40, 40, 40), + RGB(208, 208, 208)); + return TRUE; } -int sdmmc_get_cid( int isNand, uint32_t *info) +int +sdmmc_get_cid(int isNand, uint32_t* info) { - struct mmcdevice *device; - if(isNand) - device = &handelNAND; - else - device = &handelSD; - - inittarget(device); - // use cmd7 to put sd card in standby mode - // CMD7 - { - sdmmc_send_command(device,0x10507,0); - //if((device->error & 0x4)) return -1; - } - - // get sd card info - // use cmd10 to read CID - { - sdmmc_send_command(device,0x1060A,device->initarg << 0x10); - //if((device->error & 0x4)) return -2; - - for( int i = 0; i < 4; ++i ) { - info[i] = device->ret[i]; - } - } - - // put sd card back to transfer mode - // CMD7 - { - sdmmc_send_command(device,0x10507,device->initarg << 0x10); - //if((device->error & 0x4)) return -3; - } - - if(isNand) - { - inittarget(&handelSD); - } - - return 0; + struct mmcdevice* device; + if (isNand) + device = &handelNAND; + else + device = &handelSD; + + inittarget(device); + // use cmd7 to put sd card in standby mode + // CMD7 + { + sdmmc_send_command(device, 0x10507, 0); + // if((device->error & 0x4)) return -1; + } + + // get sd card info + // use cmd10 to read CID + { + sdmmc_send_command(device, 0x1060A, device->initarg << 0x10); + // if((device->error & 0x4)) return -2; + + for (int i = 0; i < 4; ++i) { + info[i] = device->ret[i]; + } + } + + // put sd card back to transfer mode + // CMD7 + { + sdmmc_send_command(device, 0x10507, device->initarg << 0x10); + // if((device->error & 0x4)) return -3; + } + + if (isNand) { + inittarget(&handelSD); + } + + return 0; } diff --git a/source/fatfs/sdmmc.h b/source/fatfs/sdmmc.h index e440bdf..7a1dc5c 100644 --- a/source/fatfs/sdmmc.h +++ b/source/fatfs/sdmmc.h @@ -6,181 +6,199 @@ #include -#define SDMMC_BASE 0x10006000 - -#define REG_SDCMD 0x00 -#define REG_SDPORTSEL 0x02 -#define REG_SDCMDARG 0x04 -#define REG_SDCMDARG0 0x04 -#define REG_SDCMDARG1 0x06 -#define REG_SDSTOP 0x08 -#define REG_SDBLKCOUNT 0x0a - -#define REG_SDRESP0 0x0c -#define REG_SDRESP1 0x0e -#define REG_SDRESP2 0x10 -#define REG_SDRESP3 0x12 -#define REG_SDRESP4 0x14 -#define REG_SDRESP5 0x16 -#define REG_SDRESP6 0x18 -#define REG_SDRESP7 0x1a - -#define REG_SDSTATUS0 0x1c -#define REG_SDSTATUS1 0x1e - -#define REG_SDIRMASK0 0x20 -#define REG_SDIRMASK1 0x22 -#define REG_SDCLKCTL 0x24 - -#define REG_SDBLKLEN 0x26 -#define REG_SDOPT 0x28 -#define REG_SDFIFO 0x30 - -#define REG_DATACTL 0xd8 -#define REG_SDRESET 0xe0 -#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not? - -#define REG_DATACTL32 0x100 -#define REG_SDBLKLEN32 0x104 -#define REG_SDBLKCOUNT32 0x108 -#define REG_SDFIFO32 0x10C - -#define REG_CLK_AND_WAIT_CTL 0x138 -#define REG_RESET_SDIO 0x1e0 - -#define TMIO_STAT0_CMDRESPEND 0x0001 -#define TMIO_STAT0_DATAEND 0x0004 -#define TMIO_STAT0_CARD_REMOVE 0x0008 -#define TMIO_STAT0_CARD_INSERT 0x0010 -#define TMIO_STAT0_SIGSTATE 0x0020 -#define TMIO_STAT0_WRPROTECT 0x0080 +#define SDMMC_BASE 0x10006000 + +#define REG_SDCMD 0x00 +#define REG_SDPORTSEL 0x02 +#define REG_SDCMDARG 0x04 +#define REG_SDCMDARG0 0x04 +#define REG_SDCMDARG1 0x06 +#define REG_SDSTOP 0x08 +#define REG_SDBLKCOUNT 0x0a + +#define REG_SDRESP0 0x0c +#define REG_SDRESP1 0x0e +#define REG_SDRESP2 0x10 +#define REG_SDRESP3 0x12 +#define REG_SDRESP4 0x14 +#define REG_SDRESP5 0x16 +#define REG_SDRESP6 0x18 +#define REG_SDRESP7 0x1a + +#define REG_SDSTATUS0 0x1c +#define REG_SDSTATUS1 0x1e + +#define REG_SDIRMASK0 0x20 +#define REG_SDIRMASK1 0x22 +#define REG_SDCLKCTL 0x24 + +#define REG_SDBLKLEN 0x26 +#define REG_SDOPT 0x28 +#define REG_SDFIFO 0x30 + +#define REG_DATACTL 0xd8 +#define REG_SDRESET 0xe0 +#define REG_SDPROTECTED 0xf6 // bit 0 determines if sd is protected or not? + +#define REG_DATACTL32 0x100 +#define REG_SDBLKLEN32 0x104 +#define REG_SDBLKCOUNT32 0x108 +#define REG_SDFIFO32 0x10C + +#define REG_CLK_AND_WAIT_CTL 0x138 +#define REG_RESET_SDIO 0x1e0 + +#define TMIO_STAT0_CMDRESPEND 0x0001 +#define TMIO_STAT0_DATAEND 0x0004 +#define TMIO_STAT0_CARD_REMOVE 0x0008 +#define TMIO_STAT0_CARD_INSERT 0x0010 +#define TMIO_STAT0_SIGSTATE 0x0020 +#define TMIO_STAT0_WRPROTECT 0x0080 #define TMIO_STAT0_CARD_REMOVE_A 0x0100 #define TMIO_STAT0_CARD_INSERT_A 0x0200 -#define TMIO_STAT0_SIGSTATE_A 0x0400 -#define TMIO_STAT1_CMD_IDX_ERR 0x0001 -#define TMIO_STAT1_CRCFAIL 0x0002 -#define TMIO_STAT1_STOPBIT_ERR 0x0004 -#define TMIO_STAT1_DATATIMEOUT 0x0008 -#define TMIO_STAT1_RXOVERFLOW 0x0010 -#define TMIO_STAT1_TXUNDERRUN 0x0020 -#define TMIO_STAT1_CMDTIMEOUT 0x0040 -#define TMIO_STAT1_RXRDY 0x0100 -#define TMIO_STAT1_TXRQ 0x0200 -#define TMIO_STAT1_ILL_FUNC 0x2000 -#define TMIO_STAT1_CMD_BUSY 0x4000 -#define TMIO_STAT1_ILL_ACCESS 0x8000 - -//Comes from TWLSDK mongoose.tef DWARF info -#define SDMC_NORMAL 0x00000000 -#define SDMC_ERR_COMMAND 0x00000001 -#define SDMC_ERR_CRC 0x00000002 -#define SDMC_ERR_END 0x00000004 -#define SDMC_ERR_TIMEOUT 0x00000008 -#define SDMC_ERR_FIFO_OVF 0x00000010 -#define SDMC_ERR_FIFO_UDF 0x00000020 -#define SDMC_ERR_WP 0x00000040 -#define SDMC_ERR_ABORT 0x00000080 -#define SDMC_ERR_FPGA_TIMEOUT 0x00000100 -#define SDMC_ERR_PARAM 0x00000200 -#define SDMC_ERR_R1_STATUS 0x00000800 -#define SDMC_ERR_NUM_WR_SECTORS 0x00001000 -#define SDMC_ERR_RESET 0x00002000 -#define SDMC_ERR_ILA 0x00004000 -#define SDMC_ERR_INFO_DETECT 0x00008000 - -#define SDMC_STAT_ERR_UNKNOWN 0x00080000 -#define SDMC_STAT_ERR_CC 0x00100000 +#define TMIO_STAT0_SIGSTATE_A 0x0400 +#define TMIO_STAT1_CMD_IDX_ERR 0x0001 +#define TMIO_STAT1_CRCFAIL 0x0002 +#define TMIO_STAT1_STOPBIT_ERR 0x0004 +#define TMIO_STAT1_DATATIMEOUT 0x0008 +#define TMIO_STAT1_RXOVERFLOW 0x0010 +#define TMIO_STAT1_TXUNDERRUN 0x0020 +#define TMIO_STAT1_CMDTIMEOUT 0x0040 +#define TMIO_STAT1_RXRDY 0x0100 +#define TMIO_STAT1_TXRQ 0x0200 +#define TMIO_STAT1_ILL_FUNC 0x2000 +#define TMIO_STAT1_CMD_BUSY 0x4000 +#define TMIO_STAT1_ILL_ACCESS 0x8000 + +// Comes from TWLSDK mongoose.tef DWARF info +#define SDMC_NORMAL 0x00000000 +#define SDMC_ERR_COMMAND 0x00000001 +#define SDMC_ERR_CRC 0x00000002 +#define SDMC_ERR_END 0x00000004 +#define SDMC_ERR_TIMEOUT 0x00000008 +#define SDMC_ERR_FIFO_OVF 0x00000010 +#define SDMC_ERR_FIFO_UDF 0x00000020 +#define SDMC_ERR_WP 0x00000040 +#define SDMC_ERR_ABORT 0x00000080 +#define SDMC_ERR_FPGA_TIMEOUT 0x00000100 +#define SDMC_ERR_PARAM 0x00000200 +#define SDMC_ERR_R1_STATUS 0x00000800 +#define SDMC_ERR_NUM_WR_SECTORS 0x00001000 +#define SDMC_ERR_RESET 0x00002000 +#define SDMC_ERR_ILA 0x00004000 +#define SDMC_ERR_INFO_DETECT 0x00008000 + +#define SDMC_STAT_ERR_UNKNOWN 0x00080000 +#define SDMC_STAT_ERR_CC 0x00100000 #define SDMC_STAT_ERR_ECC_FAILED 0x00200000 -#define SDMC_STAT_ERR_CRC 0x00800000 -#define SDMC_STAT_ERR_OTHER 0xf9c70008 +#define SDMC_STAT_ERR_CRC 0x00800000 +#define SDMC_STAT_ERR_OTHER 0xf9c70008 -#define TMIO_MASK_ALL 0x837f031d +#define TMIO_MASK_ALL 0x837f031d -#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \ - TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR) +#define TMIO_MASK_GW \ + (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | \ + TMIO_STAT1_RXOVERFLOW | TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | \ + TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR) -#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND) +#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND) #define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND) #ifdef __cplusplus extern "C" { #endif - typedef struct mmcdevice { - uint8_t* data; - uint32_t size; - uint32_t error; - uint16_t stat0; - uint16_t stat1; - uint32_t ret[4]; - uint32_t initarg; - uint32_t isSDHC; - uint32_t clk; - uint32_t SDOPT; - uint32_t devicenumber; - uint32_t total_size; //size in sectors of the device - uint32_t res; - } mmcdevice; - - int sdmmc_sdcard_init(); - int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out); - int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out); - int sdmmc_sdcard_writesector(uint32_t sector_no, uint8_t *in); - int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in); - - int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out); - int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in); - - int sdmmc_get_cid( int isNand, uint32_t *info); - - mmcdevice *getMMCDevice(int drive); - - void InitSD(); - int Nand_Init(); - int SD_Init(); +typedef struct mmcdevice +{ + uint8_t* data; + uint32_t size; + uint32_t error; + uint16_t stat0; + uint16_t stat1; + uint32_t ret[4]; + uint32_t initarg; + uint32_t isSDHC; + uint32_t clk; + uint32_t SDOPT; + uint32_t devicenumber; + uint32_t total_size; // size in sectors of the device + uint32_t res; +} mmcdevice; + +int sdmmc_sdcard_init(); +int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t* out); +int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, + uint8_t* out); +int sdmmc_sdcard_writesector(uint32_t sector_no, uint8_t* in); +int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, + uint8_t* in); + +int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, + uint8_t* out); +int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, + uint8_t* in); + +int sdmmc_get_cid(int isNand, uint32_t* info); + +mmcdevice* getMMCDevice(int drive); + +void InitSD(); +int Nand_Init(); +int SD_Init(); #ifdef __cplusplus }; #endif //--------------------------------------------------------------------------------- -static inline uint16_t sdmmc_read16(uint16_t reg) { -//--------------------------------------------------------------------------------- - return *(volatile uint16_t*)(SDMMC_BASE + reg); +static inline uint16_t +sdmmc_read16(uint16_t reg) +{ + //--------------------------------------------------------------------------------- + return *(volatile uint16_t*)(SDMMC_BASE + reg); } //--------------------------------------------------------------------------------- -static inline void sdmmc_write16(uint16_t reg, uint16_t val) { -//--------------------------------------------------------------------------------- - *(volatile uint16_t*)(SDMMC_BASE + reg) = val; +static inline void +sdmmc_write16(uint16_t reg, uint16_t val) +{ + //--------------------------------------------------------------------------------- + *(volatile uint16_t*)(SDMMC_BASE + reg) = val; } //--------------------------------------------------------------------------------- -static inline uint32_t sdmmc_read32(uint16_t reg) { -//--------------------------------------------------------------------------------- - return *(volatile uint32_t*)(SDMMC_BASE + reg); +static inline uint32_t +sdmmc_read32(uint16_t reg) +{ + //--------------------------------------------------------------------------------- + return *(volatile uint32_t*)(SDMMC_BASE + reg); } //--------------------------------------------------------------------------------- -static inline void sdmmc_write32(uint16_t reg, uint32_t val) { -//--------------------------------------------------------------------------------- - *(volatile uint32_t*)(SDMMC_BASE + reg) = val; +static inline void +sdmmc_write32(uint16_t reg, uint32_t val) +{ + //--------------------------------------------------------------------------------- + *(volatile uint32_t*)(SDMMC_BASE + reg) = val; } //--------------------------------------------------------------------------------- -static inline void sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) { -//--------------------------------------------------------------------------------- - uint16_t val = sdmmc_read16(reg); - val &= ~clear; - val |= set; - sdmmc_write16(reg, val); +static inline void +sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) +{ + //--------------------------------------------------------------------------------- + uint16_t val = sdmmc_read16(reg); + val &= ~clear; + val |= set; + sdmmc_write16(reg, val); } -static inline void setckl(uint32_t data) +static inline void +setckl(uint32_t data) { - sdmmc_mask16(REG_SDCLKCTL,0x100,0); - sdmmc_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF); - sdmmc_mask16(REG_SDCLKCTL,0x0,0x100); + sdmmc_mask16(REG_SDCLKCTL, 0x100, 0); + sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF); + sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100); } #endif diff --git a/source/firm/crypto.c b/source/firm/crypto.c index ee929ae..2451287 100644 --- a/source/firm/crypto.c +++ b/source/firm/crypto.c @@ -7,379 +7,380 @@ /* original version by megazig */ #ifndef __thumb__ -#define BSWAP32(x) {\ - __asm__\ - (\ - "eor r1, %1, %1, ror #16\n\t"\ - "bic r1, r1, #0xFF0000\n\t"\ - "mov %0, %1, ror #8\n\t"\ - "eor %0, %0, r1, lsr #8\n\t"\ - :"=r"(x)\ - :"0"(x)\ - :"r1"\ - );\ -}; - -#define ADD_u128_uint32_t(u128_0, u128_1, u128_2, u128_3, uint32_t_0) {\ -__asm__\ - (\ - "adds %0, %4\n\t"\ - "addcss %1, %1, #1\n\t"\ - "addcss %2, %2, #1\n\t"\ - "addcs %3, %3, #1\n\t"\ - : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ - : "r"(uint32_t_0)\ - : "cc"\ - );\ -} +#define BSWAP32(x) \ + { \ + __asm__("eor r1, %1, %1, ror #16\n\t" \ + "bic r1, r1, #0xFF0000\n\t" \ + "mov %0, %1, ror #8\n\t" \ + "eor %0, %0, r1, lsr #8\n\t" \ + : "=r"(x) \ + : "0"(x) \ + : "r1"); \ + }; + +#define ADD_u128_uint32_t(u128_0, u128_1, u128_2, u128_3, uint32_t_0) \ + { \ + __asm__("adds %0, %4\n\t" \ + "addcss %1, %1, #1\n\t" \ + "addcss %2, %2, #1\n\t" \ + "addcs %3, %3, #1\n\t" \ + : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3) \ + : "r"(uint32_t_0) \ + : "cc"); \ + } #else -#define BSWAP32(x) {x = __builtin_bswap32(x);} - -#define ADD_u128_uint32_t(u128_0, u128_1, u128_2, u128_3, uint32_t_0) {\ -__asm__\ - (\ - "mov r4, #0\n\t"\ - "add %0, %0, %4\n\t"\ - "adc %1, %1, r4\n\t"\ - "adc %2, %2, r4\n\t"\ - "adc %3, %3, r4\n\t"\ - : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ - : "r"(uint32_t_0)\ - : "cc", "r4"\ - );\ -} +#define BSWAP32(x) \ + { \ + x = __builtin_bswap32(x); \ + } + +#define ADD_u128_uint32_t(u128_0, u128_1, u128_2, u128_3, uint32_t_0) \ + { \ + __asm__("mov r4, #0\n\t" \ + "add %0, %0, %4\n\t" \ + "adc %1, %1, r4\n\t" \ + "adc %2, %2, r4\n\t" \ + "adc %3, %3, r4\n\t" \ + : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3) \ + : "r"(uint32_t_0) \ + : "cc", "r4"); \ + } #endif /*__thumb__*/ -void aes_setkey(uint8_t keyslot, const void* key, uint32_t keyType, uint32_t mode) +void +aes_setkey(uint8_t keyslot, const void* key, uint32_t keyType, uint32_t mode) { - if(keyslot <= 0x03) return; // Ignore TWL keys for now - - uint32_t* key32 = (uint32_t*)key; - *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; - *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE; - - REG_AESKEYFIFO[keyType] = key32[0]; - REG_AESKEYFIFO[keyType] = key32[1]; - REG_AESKEYFIFO[keyType] = key32[2]; - REG_AESKEYFIFO[keyType] = key32[3]; + if (keyslot <= 0x03) + return; // Ignore TWL keys for now + + uint32_t* key32 = (uint32_t*)key; + *REG_AESCNT = + (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; + *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE; + + REG_AESKEYFIFO[keyType] = key32[0]; + REG_AESKEYFIFO[keyType] = key32[1]; + REG_AESKEYFIFO[keyType] = key32[2]; + REG_AESKEYFIFO[keyType] = key32[3]; } -void aes_use_keyslot(uint8_t keyslot) +void +aes_use_keyslot(uint8_t keyslot) { - if(keyslot > 0x3F) - return; + if (keyslot > 0x3F) + return; - *REG_AESKEYSEL = keyslot; - *REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */ + *REG_AESKEYSEL = keyslot; + *REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */ } -void aes_setiv(const void* iv, uint32_t mode) +void +aes_setiv(const void* iv, uint32_t mode) { - const uint32_t* iv32 = (const uint32_t*)iv; - *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; - - // Word order for IV can't be changed in REG_AESCNT and always default to reversed - if(mode & AES_INPUT_NORMAL) - { - REG_AESCTR[0] = iv32[3]; - REG_AESCTR[1] = iv32[2]; - REG_AESCTR[2] = iv32[1]; - REG_AESCTR[3] = iv32[0]; - } - else - { - REG_AESCTR[0] = iv32[0]; - REG_AESCTR[1] = iv32[1]; - REG_AESCTR[2] = iv32[2]; - REG_AESCTR[3] = iv32[3]; - } + const uint32_t* iv32 = (const uint32_t*)iv; + *REG_AESCNT = + (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; + + // Word order for IV can't be changed in REG_AESCNT and always default to + // reversed + if (mode & AES_INPUT_NORMAL) { + REG_AESCTR[0] = iv32[3]; + REG_AESCTR[1] = iv32[2]; + REG_AESCTR[2] = iv32[1]; + REG_AESCTR[3] = iv32[0]; + } else { + REG_AESCTR[0] = iv32[0]; + REG_AESCTR[1] = iv32[1]; + REG_AESCTR[2] = iv32[2]; + REG_AESCTR[3] = iv32[3]; + } } -void aes_advctr(void* ctr, uint32_t val, uint32_t mode) +void +aes_advctr(void* ctr, uint32_t val, uint32_t mode) { - uint32_t* ctr32 = (uint32_t*)ctr; - - int i; - if(mode & AES_INPUT_BE) - { - for(i = 0; i < 4; ++i) // Endian swap - BSWAP32(ctr32[i]); - } - - if(mode & AES_INPUT_NORMAL) - { - ADD_u128_uint32_t(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val); - } - else - { - ADD_u128_uint32_t(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val); - } - - if(mode & AES_INPUT_BE) - { - for(i = 0; i < 4; ++i) // Endian swap - BSWAP32(ctr32[i]); - } + uint32_t* ctr32 = (uint32_t*)ctr; + + int i; + if (mode & AES_INPUT_BE) { + for (i = 0; i < 4; ++i) // Endian swap + BSWAP32(ctr32[i]); + } + + if (mode & AES_INPUT_NORMAL) { + ADD_u128_uint32_t(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val); + } else { + ADD_u128_uint32_t(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val); + } + + if (mode & AES_INPUT_BE) { + for (i = 0; i < 4; ++i) // Endian swap + BSWAP32(ctr32[i]); + } } -void aes_change_ctrmode(void* ctr, uint32_t fromMode, uint32_t toMode) +void +aes_change_ctrmode(void* ctr, uint32_t fromMode, uint32_t toMode) { - uint32_t* ctr32 = (uint32_t*)ctr; - int i; - if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN) - { - for(i = 0; i < 4; ++i) - BSWAP32(ctr32[i]); - } - - if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER) - { - uint32_t temp = ctr32[0]; - ctr32[0] = ctr32[3]; - ctr32[3] = temp; - - temp = ctr32[1]; - ctr32[1] = ctr32[2]; - ctr32[2] = temp; - } + uint32_t* ctr32 = (uint32_t*)ctr; + int i; + if ((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN) { + for (i = 0; i < 4; ++i) + BSWAP32(ctr32[i]); + } + + if ((fromMode ^ toMode) & AES_CNT_INPUT_ORDER) { + uint32_t temp = ctr32[0]; + ctr32[0] = ctr32[3]; + ctr32[3] = temp; + + temp = ctr32[1]; + ctr32[1] = ctr32[2]; + ctr32[2] = temp; + } } -void aes_batch(void* dst, const void* src, uint32_t blockCount) +void +aes_batch(void* dst, const void* src, uint32_t blockCount) { - *REG_AESBLKCNT = blockCount << 16; - *REG_AESCNT |= AES_CNT_START; - - const uint32_t* src32 = (const uint32_t*)src; - uint32_t* dst32 = (uint32_t*)dst; - - uint32_t wbc = blockCount; - uint32_t rbc = blockCount; - - while(rbc) - { - if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints - { - *REG_AESWRFIFO = *src32++; - *REG_AESWRFIFO = *src32++; - *REG_AESWRFIFO = *src32++; - *REG_AESWRFIFO = *src32++; - wbc--; - } - - if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read - { - *dst32++ = *REG_AESRDFIFO; - *dst32++ = *REG_AESRDFIFO; - *dst32++ = *REG_AESRDFIFO; - *dst32++ = *REG_AESRDFIFO; - rbc--; - } - } + *REG_AESBLKCNT = blockCount << 16; + *REG_AESCNT |= AES_CNT_START; + + const uint32_t* src32 = (const uint32_t*)src; + uint32_t* dst32 = (uint32_t*)dst; + + uint32_t wbc = blockCount; + uint32_t rbc = blockCount; + + while (rbc) { + if (wbc && + ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints + { + *REG_AESWRFIFO = *src32++; + *REG_AESWRFIFO = *src32++; + *REG_AESWRFIFO = *src32++; + *REG_AESWRFIFO = *src32++; + wbc--; + } + + if (rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= + (0x4 << 0x5))) // At least 4 ints available for read + { + *dst32++ = *REG_AESRDFIFO; + *dst32++ = *REG_AESRDFIFO; + *dst32++ = *REG_AESRDFIFO; + *dst32++ = *REG_AESRDFIFO; + rbc--; + } + } } -inline void aes_setmode(uint32_t mode) +inline void +aes_setmode(uint32_t mode) { - *REG_AESCNT = mode | - AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | - AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN | - AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE; + *REG_AESCNT = mode | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | + AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN | + AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE; } -void aes(void* dst, const void* src, uint32_t blockCount, void* iv, uint32_t mode, uint32_t ivMode) +void +aes(void* dst, const void* src, uint32_t blockCount, void* iv, uint32_t mode, + uint32_t ivMode) { - aes_setmode(mode); - - uint32_t blocks; - while(blockCount != 0) - { - if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE - && (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE) - aes_setiv(iv, ivMode); - - blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount; - - // Save the last block for the next decryption CBC batch's iv - if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE) - { - memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); - aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); - } - - // Process the current batch - aes_batch(dst, src, blocks); - - // Save the last block for the next encryption CBC batch's iv - if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE) - { - memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); - aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); - } - - // Advance counter for CTR mode - else if((mode & AES_ALL_MODES) == AES_CTR_MODE) - aes_advctr(iv, blocks, ivMode); - - src += blocks * AES_BLOCK_SIZE; - dst += blocks * AES_BLOCK_SIZE; - blockCount -= blocks; - } + aes_setmode(mode); + + uint32_t blocks; + while (blockCount != 0) { + if ((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE && + (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE) + aes_setiv(iv, ivMode); + + blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount; + + // Save the last block for the next decryption CBC batch's iv + if ((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE) { + memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); + aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); + } + + // Process the current batch + aes_batch(dst, src, blocks); + + // Save the last block for the next encryption CBC batch's iv + if ((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE) { + memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); + aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); + } + + // Advance counter for CTR mode + else if ((mode & AES_ALL_MODES) == AES_CTR_MODE) + aes_advctr(iv, blocks, ivMode); + + src += blocks * AES_BLOCK_SIZE; + dst += blocks * AES_BLOCK_SIZE; + blockCount -= blocks; + } } -void ncch_getctr(const ncch_h* ncch, uint8_t* ctr, uint8_t type) +void +ncch_getctr(const ncch_h* ncch, uint8_t* ctr, uint8_t type) { - uint32_t version = ncch->version; - const uint8_t* partitionID = ncch->partitionID; - - int i; - for(i = 0; i < 16; i++) - ctr[i] = 0x00; - - if(version == 2 || version == 0) - { - for(i=0; i<8; i++) - ctr[i] = partitionID[7 - i]; // Convert to big endian & normal input - ctr[8] = type; - } - else if(version == 1) - { - int x = 0; - if(type == NCCHTYPE_EXHEADER) - x = MEDIA_UNITS; - else if(type == NCCHTYPE_EXEFS) - x = ncch->exeFSOffset * MEDIA_UNITS; - else if (type == NCCHTYPE_ROMFS) - x = ncch->exeFSOffset * MEDIA_UNITS; - - for(i = 0; i < 8; i++) - ctr[i] = partitionID[i]; - for(i = 0; i < 4; i++) - ctr[i + 12] = (x >> ((3 - i) * 8)) & 0xFF; - } + uint32_t version = ncch->version; + const uint8_t* partitionID = ncch->partitionID; + + int i; + for (i = 0; i < 16; i++) + ctr[i] = 0x00; + + if (version == 2 || version == 0) { + for (i = 0; i < 8; i++) + ctr[i] = partitionID[7 - i]; // Convert to big endian & normal input + ctr[8] = type; + } else if (version == 1) { + int x = 0; + if (type == NCCHTYPE_EXHEADER) + x = MEDIA_UNITS; + else if (type == NCCHTYPE_EXEFS) + x = ncch->exeFSOffset * MEDIA_UNITS; + else if (type == NCCHTYPE_ROMFS) + x = ncch->exeFSOffset * MEDIA_UNITS; + + for (i = 0; i < 8; i++) + ctr[i] = partitionID[i]; + for (i = 0; i < 4; i++) + ctr[i + 12] = (x >> ((3 - i) * 8)) & 0xFF; + } } -void sha_wait_idle() +void +sha_wait_idle() { - while(*REG_SHA_CNT & 1); + while (*REG_SHA_CNT & 1) + ; } -void sha(void* res, const void* src, uint32_t size, uint32_t mode) +void +sha(void* res, const void* src, uint32_t size, uint32_t mode) { - sha_wait_idle(); - *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; - - const uint32_t* src32 = (const uint32_t*)src; - int i; - while(size >= 0x40) - { - sha_wait_idle(); - for(i = 0; i < 4; ++i) - { - *REG_SHA_INFIFO = *src32++; - *REG_SHA_INFIFO = *src32++; - *REG_SHA_INFIFO = *src32++; - *REG_SHA_INFIFO = *src32++; - } - - size -= 0x40; - } - - sha_wait_idle(); - memcpy((void*)REG_SHA_INFIFO, src32, size); - - *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; - - while(*REG_SHA_CNT & SHA_FINAL_ROUND); - sha_wait_idle(); - - uint32_t hashSize = SHA_256_HASH_SIZE; - if(mode == SHA_224_MODE) - hashSize = SHA_224_HASH_SIZE; - else if(mode == SHA_1_MODE) - hashSize = SHA_1_HASH_SIZE; - - memcpy(res, (void*)REG_SHA_HASH, hashSize); + sha_wait_idle(); + *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; + + const uint32_t* src32 = (const uint32_t*)src; + int i; + while (size >= 0x40) { + sha_wait_idle(); + for (i = 0; i < 4; ++i) { + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + *REG_SHA_INFIFO = *src32++; + } + + size -= 0x40; + } + + sha_wait_idle(); + memcpy((void*)REG_SHA_INFIFO, src32, size); + + *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; + + while (*REG_SHA_CNT & SHA_FINAL_ROUND) + ; + sha_wait_idle(); + + uint32_t hashSize = SHA_256_HASH_SIZE; + if (mode == SHA_224_MODE) + hashSize = SHA_224_HASH_SIZE; + else if (mode == SHA_1_MODE) + hashSize = SHA_1_HASH_SIZE; + + memcpy(res, (void*)REG_SHA_HASH, hashSize); } -void rsa_wait_idle() +void +rsa_wait_idle() { - while(*REG_RSA_CNT & 1); + while (*REG_RSA_CNT & 1) + ; } -void rsa_use_keyslot(uint32_t keyslot) +void +rsa_use_keyslot(uint32_t keyslot) { - *REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4); + *REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4); } -void rsa_setkey(uint32_t keyslot, const void* mod, const void* exp, uint32_t mode) +void +rsa_setkey(uint32_t keyslot, const void* mod, const void* exp, uint32_t mode) { - rsa_wait_idle(); - *REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4) | RSA_IO_BE | RSA_IO_NORMAL; - - uint32_t size = mode * 4; - - volatile uint32_t* keyslotCnt = REG_RSA_SLOT0 + (keyslot << 4); - keyslotCnt[0] &= ~(RSA_SLOTCNT_KEY_SET | RSA_SLOTCNT_WPROTECT); - keyslotCnt[1] = mode; - - memcpy((void*)REG_RSA_MOD_END - size, mod, size); - - if(exp == NULL) - { - size -= 4; - while(size) - { - *REG_RSA_EXPFIFO = 0; - size -= 4; - } - *REG_RSA_EXPFIFO = 0x01000100; // 0x00010001 byteswapped - } - else - { - const uint32_t* exp32 = (const uint32_t*)exp; - while(size) - { - *REG_RSA_EXPFIFO = *exp32++; - size -= 4; - } - } + rsa_wait_idle(); + *REG_RSA_CNT = (*REG_RSA_CNT & ~RSA_CNT_KEYSLOTS) | (keyslot << 4) | + RSA_IO_BE | RSA_IO_NORMAL; + + uint32_t size = mode * 4; + + volatile uint32_t* keyslotCnt = REG_RSA_SLOT0 + (keyslot << 4); + keyslotCnt[0] &= ~(RSA_SLOTCNT_KEY_SET | RSA_SLOTCNT_WPROTECT); + keyslotCnt[1] = mode; + + memcpy((void*)REG_RSA_MOD_END - size, mod, size); + + if (exp == NULL) { + size -= 4; + while (size) { + *REG_RSA_EXPFIFO = 0; + size -= 4; + } + *REG_RSA_EXPFIFO = 0x01000100; // 0x00010001 byteswapped + } else { + const uint32_t* exp32 = (const uint32_t*)exp; + while (size) { + *REG_RSA_EXPFIFO = *exp32++; + size -= 4; + } + } } -int rsa_iskeyset(uint32_t keyslot) +int +rsa_iskeyset(uint32_t keyslot) { - return *(REG_RSA_SLOT0 + (keyslot << 4)) & 1; + return *(REG_RSA_SLOT0 + (keyslot << 4)) & 1; } -void rsa(void* dst, const void* src, uint32_t size) +void +rsa(void* dst, const void* src, uint32_t size) { - uint32_t keyslot = (*REG_RSA_CNT & RSA_CNT_KEYSLOTS) >> 4; - if(rsa_iskeyset(keyslot) == 0) - return; - - rsa_wait_idle(); - *REG_RSA_CNT |= RSA_IO_BE | RSA_IO_NORMAL; - - // Pad the message with zeroes so that it's a multiple of 8 - // and write the message with the end aligned with the register - uint32_t padSize = ((size + 7) & ~7) - size; - memset((void*)REG_RSA_TXT_END - (size + padSize), 0, padSize); - memcpy((void*)REG_RSA_TXT_END - size, src, size); - - // Start - *REG_RSA_CNT |= RSA_CNT_START; - - rsa_wait_idle(); - memcpy(dst, (void*)REG_RSA_TXT_END - size, size); + uint32_t keyslot = (*REG_RSA_CNT & RSA_CNT_KEYSLOTS) >> 4; + if (rsa_iskeyset(keyslot) == 0) + return; + + rsa_wait_idle(); + *REG_RSA_CNT |= RSA_IO_BE | RSA_IO_NORMAL; + + // Pad the message with zeroes so that it's a multiple of 8 + // and write the message with the end aligned with the register + uint32_t padSize = ((size + 7) & ~7) - size; + memset((void*)REG_RSA_TXT_END - (size + padSize), 0, padSize); + memcpy((void*)REG_RSA_TXT_END - size, src, size); + + // Start + *REG_RSA_CNT |= RSA_CNT_START; + + rsa_wait_idle(); + memcpy(dst, (void*)REG_RSA_TXT_END - size, size); } -int rsa_verify(const void* data, uint32_t size, const void* sig, uint32_t mode) +int +rsa_verify(const void* data, uint32_t size, const void* sig, uint32_t mode) { - uint8_t dataHash[SHA_256_HASH_SIZE]; - sha(dataHash, data, size, SHA_256_MODE); - - uint8_t decSig[0x100]; // Way too big, need to request a work area - - uint32_t sigSize = mode * 4; - rsa(decSig, sig, sigSize); - - return memcmp(dataHash, decSig + (sigSize - SHA_256_HASH_SIZE), SHA_256_HASH_SIZE) == 0; + uint8_t dataHash[SHA_256_HASH_SIZE]; + sha(dataHash, data, size, SHA_256_MODE); + + uint8_t decSig[0x100]; // Way too big, need to request a work area + + uint32_t sigSize = mode * 4; + rsa(decSig, sig, sigSize); + + return memcmp(dataHash, decSig + (sigSize - SHA_256_HASH_SIZE), + SHA_256_HASH_SIZE) == 0; } diff --git a/source/firm/crypto.h b/source/firm/crypto.h index ba490f9..e4ea043 100644 --- a/source/firm/crypto.h +++ b/source/firm/crypto.h @@ -7,110 +7,112 @@ #include "headers.h" /**************************AES****************************/ -#define REG_AESCNT ((volatile uint32_t*)0x10009000) -#define REG_AESBLKCNT ((volatile uint32_t*)0x10009004) -#define REG_AESWRFIFO ((volatile uint32_t*)0x10009008) -#define REG_AESRDFIFO ((volatile uint32_t*)0x1000900C) -#define REG_AESKEYSEL ((volatile uint8_t *)0x10009010) -#define REG_AESKEYCNT ((volatile uint8_t *)0x10009011) -#define REG_AESCTR ((volatile uint32_t*)0x10009020) - -#define REG_AESKEYFIFO ((volatile uint32_t*)0x10009100) -#define REG_AESKEYXFIFO ((volatile uint32_t*)0x10009104) -#define REG_AESKEYYFIFO ((volatile uint32_t*)0x10009108) - -#define AES_CCM_DECRYPT_MODE (0u << 27) -#define AES_CCM_ENCRYPT_MODE (1u << 27) -#define AES_CTR_MODE (2u << 27) -#define AES_CTR_MODE (2u << 27) -#define AES_CBC_DECRYPT_MODE (4u << 27) -#define AES_CBC_ENCRYPT_MODE (5u << 27) -#define AES_ECB_DECRYPT_MODE (6u << 27) -#define AES_ECB_ENCRYPT_MODE (7u << 27) -#define AES_ALL_MODES (7u << 27) - -#define AES_CNT_START 0x80000000 -#define AES_CNT_INPUT_ORDER 0x02000000 -#define AES_CNT_OUTPUT_ORDER 0x01000000 -#define AES_CNT_INPUT_ENDIAN 0x00800000 -#define AES_CNT_OUTPUT_ENDIAN 0x00400000 -#define AES_CNT_FLUSH_READ 0x00000800 -#define AES_CNT_FLUSH_WRITE 0x00000400 - -#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN) -#define AES_INPUT_LE 0 -#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER) -#define AES_INPUT_REVERSED 0 - -#define AES_TEMP_KEYSLOT 0x11 - -#define AES_BLOCK_SIZE 0x10 - -#define AES_KEYCNT_WRITE (1 << 0x7) -#define AES_KEYNORMAL 0 -#define AES_KEYX 1 -#define AES_KEYY 2 +#define REG_AESCNT ((volatile uint32_t*)0x10009000) +#define REG_AESBLKCNT ((volatile uint32_t*)0x10009004) +#define REG_AESWRFIFO ((volatile uint32_t*)0x10009008) +#define REG_AESRDFIFO ((volatile uint32_t*)0x1000900C) +#define REG_AESKEYSEL ((volatile uint8_t*)0x10009010) +#define REG_AESKEYCNT ((volatile uint8_t*)0x10009011) +#define REG_AESCTR ((volatile uint32_t*)0x10009020) + +#define REG_AESKEYFIFO ((volatile uint32_t*)0x10009100) +#define REG_AESKEYXFIFO ((volatile uint32_t*)0x10009104) +#define REG_AESKEYYFIFO ((volatile uint32_t*)0x10009108) + +#define AES_CCM_DECRYPT_MODE (0u << 27) +#define AES_CCM_ENCRYPT_MODE (1u << 27) +#define AES_CTR_MODE (2u << 27) +#define AES_CTR_MODE (2u << 27) +#define AES_CBC_DECRYPT_MODE (4u << 27) +#define AES_CBC_ENCRYPT_MODE (5u << 27) +#define AES_ECB_DECRYPT_MODE (6u << 27) +#define AES_ECB_ENCRYPT_MODE (7u << 27) +#define AES_ALL_MODES (7u << 27) + +#define AES_CNT_START 0x80000000 +#define AES_CNT_INPUT_ORDER 0x02000000 +#define AES_CNT_OUTPUT_ORDER 0x01000000 +#define AES_CNT_INPUT_ENDIAN 0x00800000 +#define AES_CNT_OUTPUT_ENDIAN 0x00400000 +#define AES_CNT_FLUSH_READ 0x00000800 +#define AES_CNT_FLUSH_WRITE 0x00000400 + +#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN) +#define AES_INPUT_LE 0 +#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER) +#define AES_INPUT_REVERSED 0 + +#define AES_TEMP_KEYSLOT 0x11 + +#define AES_BLOCK_SIZE 0x10 + +#define AES_KEYCNT_WRITE (1 << 0x7) +#define AES_KEYNORMAL 0 +#define AES_KEYX 1 +#define AES_KEYY 2 /**************************SHA****************************/ -#define REG_SHA_CNT ((volatile uint32_t*)0x1000A000) -#define REG_SHA_BLKCNT ((volatile uint32_t*)0x1000A004) -#define REG_SHA_HASH ((volatile uint32_t*)0x1000A040) -#define REG_SHA_INFIFO ((volatile uint32_t*)0x1000A080) +#define REG_SHA_CNT ((volatile uint32_t*)0x1000A000) +#define REG_SHA_BLKCNT ((volatile uint32_t*)0x1000A004) +#define REG_SHA_HASH ((volatile uint32_t*)0x1000A040) +#define REG_SHA_INFIFO ((volatile uint32_t*)0x1000A080) -#define SHA_CNT_STATE 0x00000003 -#define SHA_CNT_UNK2 0x00000004 -#define SHA_CNT_OUTPUT_ENDIAN 0x00000008 -#define SHA_CNT_MODE 0x00000030 -#define SHA_CNT_ENABLE 0x00010000 -#define SHA_CNT_ACTIVE 0x00020000 +#define SHA_CNT_STATE 0x00000003 +#define SHA_CNT_UNK2 0x00000004 +#define SHA_CNT_OUTPUT_ENDIAN 0x00000008 +#define SHA_CNT_MODE 0x00000030 +#define SHA_CNT_ENABLE 0x00010000 +#define SHA_CNT_ACTIVE 0x00020000 -#define SHA_HASH_READY 0x00000000 -#define SHA_NORMAL_ROUND 0x00000001 -#define SHA_FINAL_ROUND 0x00000002 +#define SHA_HASH_READY 0x00000000 +#define SHA_NORMAL_ROUND 0x00000001 +#define SHA_FINAL_ROUND 0x00000002 -#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN -#define SHA_OUTPUT_LE 0 +#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN +#define SHA_OUTPUT_LE 0 -#define SHA_256_MODE 0 -#define SHA_224_MODE 0x00000010 -#define SHA_1_MODE 0x00000020 +#define SHA_256_MODE 0 +#define SHA_224_MODE 0x00000010 +#define SHA_1_MODE 0x00000020 -#define SHA_256_HASH_SIZE (256 / 8) -#define SHA_224_HASH_SIZE (224 / 8) -#define SHA_1_HASH_SIZE (160 / 8) +#define SHA_256_HASH_SIZE (256 / 8) +#define SHA_224_HASH_SIZE (224 / 8) +#define SHA_1_HASH_SIZE (160 / 8) /**************************RSA****************************/ -#define REG_RSA_CNT ((volatile uint32_t*)0x1000B000) -#define REG_RSA_SLOT0 ((volatile uint32_t*)0x1000B100) -#define REG_RSA_SLOT1 ((volatile uint32_t*)0x1000B110) -#define REG_RSA_SLOT2 ((volatile uint32_t*)0x1000B120) -#define REG_RSA_SLOT3 ((volatile uint32_t*)0x1000B130) -#define REG_RSA_EXPFIFO ((volatile uint32_t*)0x1000B200) -#define REG_RSA_MOD_END ((volatile uint32_t*)0x1000B500) -#define REG_RSA_TXT_END ((volatile uint32_t*)0x1000B900) - -#define RSA_CNT_START 0x00000001 -#define RSA_CNT_KEYSLOTS 0x000000F0 -#define RSA_CNT_IO_ENDIAN 0x00000100 -#define RSA_CNT_IO_ORDER 0x00000200 - -#define RSA_SLOTCNT_KEY_SET 0x00000001 -#define RSA_SLOTCNT_WPROTECT 0x00000002 // Write protect - -#define RSA_IO_BE RSA_CNT_IO_ENDIAN -#define RSA_IO_LE 0 -#define RSA_IO_NORMAL RSA_CNT_IO_ORDER -#define RSA_IO_REVERSED 0 - -#define RSA_TEMP_KEYSLOT 0 - -#define RSA_1024_MODE 0x20 -#define RSA_2048_MODE 0x40 - -void aes_setkey(uint8_t keyslot, const void* key, uint32_t keyType, uint32_t mode); +#define REG_RSA_CNT ((volatile uint32_t*)0x1000B000) +#define REG_RSA_SLOT0 ((volatile uint32_t*)0x1000B100) +#define REG_RSA_SLOT1 ((volatile uint32_t*)0x1000B110) +#define REG_RSA_SLOT2 ((volatile uint32_t*)0x1000B120) +#define REG_RSA_SLOT3 ((volatile uint32_t*)0x1000B130) +#define REG_RSA_EXPFIFO ((volatile uint32_t*)0x1000B200) +#define REG_RSA_MOD_END ((volatile uint32_t*)0x1000B500) +#define REG_RSA_TXT_END ((volatile uint32_t*)0x1000B900) + +#define RSA_CNT_START 0x00000001 +#define RSA_CNT_KEYSLOTS 0x000000F0 +#define RSA_CNT_IO_ENDIAN 0x00000100 +#define RSA_CNT_IO_ORDER 0x00000200 + +#define RSA_SLOTCNT_KEY_SET 0x00000001 +#define RSA_SLOTCNT_WPROTECT 0x00000002 // Write protect + +#define RSA_IO_BE RSA_CNT_IO_ENDIAN +#define RSA_IO_LE 0 +#define RSA_IO_NORMAL RSA_CNT_IO_ORDER +#define RSA_IO_REVERSED 0 + +#define RSA_TEMP_KEYSLOT 0 + +#define RSA_1024_MODE 0x20 +#define RSA_2048_MODE 0x40 + +void aes_setkey(uint8_t keyslot, const void* key, uint32_t keyType, + uint32_t mode); void aes_use_keyslot(uint8_t keyslot); -void aes(void* dst, const void* src, uint32_t blockCount, void* iv, uint32_t mode, uint32_t ivMode); +void aes(void* dst, const void* src, uint32_t blockCount, void* iv, + uint32_t mode, uint32_t ivMode); void aes_setiv(const void* iv, uint32_t mode); void aes_advctr(void* ctr, uint32_t val, uint32_t mode); @@ -120,16 +122,16 @@ void aes_batch(void* dst, const void* src, uint32_t blockCount); void sha(void* res, const void* src, uint32_t size, uint32_t mode); -void rsa_setkey(uint32_t keyslot, const void* mod, const void* exp, uint32_t mode); +void rsa_setkey(uint32_t keyslot, const void* mod, const void* exp, + uint32_t mode); void rsa_use_keyslot(uint32_t keyslot); int rsa_verify(const void* data, uint32_t size, const void* sig, uint32_t mode); -typedef enum -{ - NCCHTYPE_EXHEADER = 1, - NCCHTYPE_EXEFS = 2, - NCCHTYPE_ROMFS = 3, +typedef enum { + NCCHTYPE_EXHEADER = 1, + NCCHTYPE_EXEFS = 2, + NCCHTYPE_ROMFS = 3, } ctr_ncchtypes; void ncch_getctr(const ncch_h* ncch, uint8_t* ctr, uint8_t type); diff --git a/source/firm/fcram.c b/source/firm/fcram.c index 6ab1f67..61ea587 100644 --- a/source/firm/fcram.c +++ b/source/firm/fcram.c @@ -1,3 +1,3 @@ #include "fcram.h" -void *fcram_temp = (void *)0x23000000; +void* fcram_temp = (void*)0x23000000; diff --git a/source/firm/fcram.h b/source/firm/fcram.h index 80f7b57..783326d 100644 --- a/source/firm/fcram.h +++ b/source/firm/fcram.h @@ -8,7 +8,7 @@ #include "../std/unused.h" -extern void *fcram_temp; +extern void* fcram_temp; // Space between most of the locations #define FCRAM_SPACING 0x100000 @@ -18,7 +18,7 @@ extern void *fcram_temp; // firm.c #define FCRAM_FIRM_LOC FCRAM_START -#define FCRAM_TWL_FIRM_LOC (FCRAM_START + FCRAM_SPACING) // Double size +#define FCRAM_TWL_FIRM_LOC (FCRAM_START + FCRAM_SPACING) // Double size #define FCRAM_AGB_FIRM_LOC (FCRAM_START + FCRAM_SPACING * 3) // patch.c diff --git a/source/firm/firm.c b/source/firm/firm.c index dfb1cf1..0bdd65b 100644 --- a/source/firm/firm.c +++ b/source/firm/firm.c @@ -5,26 +5,27 @@ #include "../common.h" -firm_h *firm_loc = (firm_h *)FCRAM_FIRM_LOC; +firm_h* firm_loc = (firm_h*)FCRAM_FIRM_LOC; static uint32_t firm_size = FCRAM_SPACING; firm_section_h firm_proc9; -exefs_h *firm_p9_exefs; +exefs_h* firm_p9_exefs; -firm_h *twl_firm_loc = (firm_h *)FCRAM_TWL_FIRM_LOC; +firm_h* twl_firm_loc = (firm_h*)FCRAM_TWL_FIRM_LOC; static uint32_t twl_firm_size = FCRAM_SPACING * 2; firm_section_h twl_firm_proc9; -exefs_h *twl_firm_p9_exefs; +exefs_h* twl_firm_p9_exefs; -firm_h *agb_firm_loc = (firm_h *)FCRAM_AGB_FIRM_LOC; +firm_h* agb_firm_loc = (firm_h*)FCRAM_AGB_FIRM_LOC; static uint32_t agb_firm_size = FCRAM_SPACING; firm_section_h agb_firm_proc9; -exefs_h *agb_firm_p9_exefs; +exefs_h* agb_firm_p9_exefs; static int update_96_keys = 0; -static volatile uint32_t *const a11_entry = (volatile uint32_t *)0x1FFFFFF8; +static volatile uint32_t* const a11_entry = (volatile uint32_t*)0x1FFFFFF8; -void slot0x11key96_init() +void +slot0x11key96_init() { // 9.6 crypto may need us to get the key from somewhere else. // Unless the console already has the key initialized, that is. @@ -37,19 +38,24 @@ void slot0x11key96_init() // Tell boot_firm it needs to regenerate the keys. update_96_keys = 1; } - // If we can't read the key, we assume it's not needed, and the firmware is the right version. - // Otherwise, we make sure the error message for decrypting arm9bin mentions this. + // If we can't read the key, we assume it's not needed, and the firmware is + // the right version. + // Otherwise, we make sure the error message for decrypting arm9bin mentions + // this. } -int decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key) { - uint8_t firm_iv[16] = {0}; - uint8_t exefs_key[16] = {0}; - uint8_t exefs_iv[16] = {0}; +int +decrypt_firm_title(firm_h* dest, ncch_h* ncch, uint32_t* size, void* key) +{ + uint8_t firm_iv[16] = { 0 }; + uint8_t exefs_key[16] = { 0 }; + uint8_t exefs_iv[16] = { 0 }; fprintf(BOTTOM_SCREEN, " Decrypting the NCCH\n"); aes_setkey(0x16, key, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes_use_keyslot(0x16); - aes(ncch, ncch, *size / AES_BLOCK_SIZE, firm_iv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes(ncch, ncch, *size / AES_BLOCK_SIZE, firm_iv, AES_CBC_DECRYPT_MODE, + AES_INPUT_BE | AES_INPUT_NORMAL); if (ncch->magic != NCCH_MAGIC) return 1; @@ -58,17 +64,19 @@ int decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key) { ncch_getctr(ncch, exefs_iv, NCCHTYPE_EXEFS); // Get the exefs offset and size from the NCCH - exefs_h *exefs = (exefs_h *)((void *)ncch + ncch->exeFSOffset * MEDIA_UNITS); + exefs_h* exefs = (exefs_h*)((void*)ncch + ncch->exeFSOffset * MEDIA_UNITS); uint32_t exefs_size = ncch->exeFSSize * MEDIA_UNITS; fprintf(BOTTOM_SCREEN, " Decrypting the exefs\n"); aes_setkey(0x2C, exefs_key, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_use_keyslot(0x2C); - aes(exefs, exefs, exefs_size / AES_BLOCK_SIZE, exefs_iv, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes(exefs, exefs, exefs_size / AES_BLOCK_SIZE, exefs_iv, AES_CTR_MODE, + AES_INPUT_BE | AES_INPUT_NORMAL); // Get the decrypted FIRM // We assume the firm.bin is always the first file - firm_h *firm = (firm_h *)&exefs[1]; // The offset right behind the exefs header; the first file. + firm_h* firm = (firm_h*)&exefs[1]; // The offset right behind the exefs + // header; the first file. *size = exefs->fileHeaders[0].size; if (firm->magic != FIRM_MAGIC) @@ -79,7 +87,9 @@ int decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key) { return 0; } -int decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title, uint8_t version) { +int +decrypt_arm9bin(arm9bin_h* header, uint64_t firm_title, uint8_t version) +{ uint8_t slot = 0x15; fprintf(BOTTOM_SCREEN, " Decrypting ARM9 FIRM binary\n"); @@ -91,27 +101,33 @@ int decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title, uint8_t version) { slot = 0x16; aes_use_keyslot(0x11); - aes(decrypted_keyx, header->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, 0); - aes_setkey(slot, decrypted_keyx, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); + aes(decrypted_keyx, header->slot0x16keyX, 1, NULL, AES_ECB_DECRYPT_MODE, + 0); + aes_setkey(slot, decrypted_keyx, AES_KEYX, + AES_INPUT_BE | AES_INPUT_NORMAL); } aes_setkey(slot, header->keyy, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setiv(header->ctr, AES_INPUT_BE | AES_INPUT_NORMAL); - void *arm9bin = (uint8_t *)header + 0x800; + void* arm9bin = (uint8_t*)header + 0x800; int size = atoi(header->size); aes_use_keyslot(slot); - aes(arm9bin, arm9bin, size / AES_BLOCK_SIZE, header->ctr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); + aes(arm9bin, arm9bin, size / AES_BLOCK_SIZE, header->ctr, AES_CTR_MODE, + AES_INPUT_BE | AES_INPUT_NORMAL); if (firm_title == NATIVE_FIRM_TITLEID) - return *(uint32_t *)arm9bin != ARM9BIN_MAGIC; + return *(uint32_t*)arm9bin != ARM9BIN_MAGIC; else if (firm_title == AGB_FIRM_TITLEID || firm_title == TWL_FIRM_TITLEID) - return *(uint32_t *)arm9bin != LGY_ARM9BIN_MAGIC; - else return 0; + return *(uint32_t*)arm9bin != LGY_ARM9BIN_MAGIC; + else + return 0; } -int decrypt_firm(firm_h *dest, char *path_firmkey, uint32_t *size) { +int +decrypt_firm(firm_h* dest, char* path_firmkey, uint32_t* size) +{ uint8_t firm_key[AES_BLOCK_SIZE]; // Firmware is likely encrypted. Decrypt. @@ -123,16 +139,19 @@ int decrypt_firm(firm_h *dest, char *path_firmkey, uint32_t *size) { } fprintf(BOTTOM_SCREEN, " Decrypting FIRM\n"); - if (decrypt_firm_title(dest, (void *)dest, size, firm_key) != 0) { + if (decrypt_firm_title(dest, (void*)dest, size, firm_key) != 0) { fprintf(BOTTOM_SCREEN, "Failed to decrypt the firmware\n"); return 1; } - return 0; + return 0; } extern int patch_services(); -int load_firm(firm_h *dest, char *path, char *path_firmkey, uint32_t *size, uint64_t firm_title) { +int +load_firm(firm_h* dest, char* path, char* path_firmkey, uint32_t* size, + uint64_t firm_title) +{ int status = 0; int firmware_changed = 0; @@ -150,15 +169,15 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, uint32_t *size, uint goto exit_error; } - // Check and decrypt FIRM if it is encrypted. + // Check and decrypt FIRM if it is encrypted. if (dest->magic != FIRM_MAGIC) { status = decrypt_firm(dest, path_firmkey, size); if (status != 0) { if (firm_title == NATIVE_FIRM_TITLEID) { fprintf(BOTTOM_SCREEN, "Failed to decrypt firmware.\n" "This is fatal. Aborting.\n"); - status = 1; - goto exit_error; + status = 1; + goto exit_error; } } firmware_changed = 1; // Decryption performed. @@ -166,38 +185,47 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, uint32_t *size, uint fprintf(BOTTOM_SCREEN, " FIRM not encrypted\n"); } - struct firm_signature* fsig = get_firm_info(dest); + struct firm_signature* fsig = get_firm_info(dest); - fprintf(BOTTOM_SCREEN, " FIRM version: %s\n", fsig->version_string); + fprintf(BOTTOM_SCREEN, " FIRM version: %s\n", fsig->version_string); // The N3DS firm has an additional encryption layer for ARM9 - if (fsig->console == console_n3ds) { + if (fsig->console == console_n3ds) { // Look for the arm9 section - for (firm_section_h *section = dest->section; - section < dest->section + 4; section++) { + for (firm_section_h* section = dest->section; + section < dest->section + 4; section++) { if (section->type == FIRM_TYPE_ARM9) { // Check whether the arm9bin is encrypted. int arm9bin_iscrypt = 0; - uint32_t magic = *(uint32_t*)((uintptr_t)dest + section->offset + 0x800); + uint32_t magic = + *(uint32_t*)((uintptr_t)dest + section->offset + 0x800); if (firm_title == NATIVE_FIRM_TITLEID) arm9bin_iscrypt = (magic != ARM9BIN_MAGIC); - else if (firm_title == AGB_FIRM_TITLEID || firm_title == TWL_FIRM_TITLEID) + else if (firm_title == AGB_FIRM_TITLEID || + firm_title == TWL_FIRM_TITLEID) arm9bin_iscrypt = (magic != LGY_ARM9BIN_MAGIC); if (arm9bin_iscrypt) { // Decrypt the arm9bin. - if (decrypt_arm9bin((arm9bin_h *)((uintptr_t)dest + section->offset), firm_title, fsig->version)) { - fprintf(BOTTOM_SCREEN, "Couldn't decrypt ARM9 FIRM binary.\n" - "Check if you have the needed key at:\n" - " " PATH_SLOT0X11KEY96 "\n"); + if (decrypt_arm9bin( + (arm9bin_h*)((uintptr_t)dest + section->offset), + firm_title, fsig->version)) { + fprintf(BOTTOM_SCREEN, + "Couldn't decrypt ARM9 FIRM binary.\n" + "Check if you have the needed key at:\n" + " " PATH_SLOT0X11KEY96 "\n"); status = 1; goto exit_error; } firmware_changed = 1; // Decryption of arm9bin performed. } else { - fprintf(BOTTOM_SCREEN, " ARM9 FIRM binary not encrypted\n"); - if (firm_title == NATIVE_FIRM_TITLEID && fsig->version > 0x0F) { - slot0x11key96_init(); // This has to be loaded regardless, otherwise boot will fail. + fprintf(BOTTOM_SCREEN, + " ARM9 FIRM binary not encrypted\n"); + if (firm_title == NATIVE_FIRM_TITLEID && + fsig->version > 0x0F) { + slot0x11key96_init(); // This has to be loaded + // regardless, otherwise boot will + // fail. } } @@ -234,117 +262,138 @@ exit_error: return status; } -void __attribute__((naked)) disable_lcds() { - *a11_entry = 0; // Don't wait for us +void __attribute__((naked)) disable_lcds() +{ + *a11_entry = 0; // Don't wait for us - *(volatile uint32_t *)0x10202A44 = 0; - *(volatile uint32_t *)0x10202244 = 0; - *(volatile uint32_t *)0x1020200C = 0; - *(volatile uint32_t *)0x10202014 = 0; + *(volatile uint32_t*)0x10202A44 = 0; + *(volatile uint32_t*)0x10202244 = 0; + *(volatile uint32_t*)0x1020200C = 0; + *(volatile uint32_t*)0x10202014 = 0; - while (!*a11_entry); - ((void (*)())*a11_entry)(); + while (!*a11_entry) + ; + ((void (*)()) * a11_entry)(); } extern void wait(); -void boot_firm() { - struct firm_signature* fsig = get_firm_info(firm_loc); +void +boot_firm() +{ + struct firm_signature* fsig = get_firm_info(firm_loc); - // Set up the keys needed to boot a few firmwares, due to them being unset, depending on which firmware you're booting from. + // Set up the keys needed to boot a few firmwares, due to them being unset, + // depending on which firmware you're booting from. // TODO: Don't use the hardcoded offset. - if (update_96_keys && fsig->console == console_n3ds && fsig->version > 0x0F) { - void *keydata = NULL; - if (fsig->version == 0x1B || fsig->version == 0x1F) { - keydata = (void *)((uintptr_t)firm_loc + firm_loc->section[2].offset + 0x89814); - } else if (fsig->version == 0x21) { - keydata = (void *)((uintptr_t)firm_loc + firm_loc->section[2].offset + 0x89A14); - } + if (update_96_keys && fsig->console == console_n3ds && + fsig->version > 0x0F) { + void* keydata = NULL; + if (fsig->version == 0x1B || fsig->version == 0x1F) { + keydata = (void*)((uintptr_t)firm_loc + + firm_loc->section[2].offset + 0x89814); + } else if (fsig->version == 0x21) { + keydata = (void*)((uintptr_t)firm_loc + + firm_loc->section[2].offset + 0x89A14); + } aes_use_keyslot(0x11); uint8_t keyx[AES_BLOCK_SIZE]; for (int slot = 0x19; slot < 0x20; slot++) { aes(keyx, keydata, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes_setkey(slot, keyx, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); - *(uint8_t *)(keydata + 0xF) += 1; + *(uint8_t*)(keydata + 0xF) += 1; } fprintf(BOTTOM_SCREEN, "Updated keyX keyslots\n"); } - fumount(); // Unmount SD. No longer needed. - fprintf(BOTTOM_SCREEN, "SD Unmounted.\n"); + fumount(); // Unmount SD. No longer needed. + fprintf(BOTTOM_SCREEN, "SD Unmounted.\n"); - for (firm_section_h *section = firm_loc->section; - section < firm_loc->section + 4 && section->address != 0; section++) { - memcpy((void *)section->address, (void *)firm_loc + section->offset, section->size); + for (firm_section_h* section = firm_loc->section; + section < firm_loc->section + 4 && section->address != 0; section++) { + memcpy((void*)section->address, (void*)firm_loc + section->offset, + section->size); } fprintf(BOTTOM_SCREEN, "Copied FIRM\n"); - wait(); + wait(); - // No fprintf will work from here on out. + // No fprintf will work from here on out. *a11_entry = (uint32_t)disable_lcds; - while (*a11_entry); // Make sure it jumped there correctly before changing it. + while (*a11_entry) + ; // Make sure it jumped there correctly before changing it. *a11_entry = (uint32_t)firm_loc->a11Entry; ((void (*)())firm_loc->a9Entry)(); } -int find_proc9(firm_h* firm, firm_section_h* process9, exefs_h** p9exefs) { - for (firm_section_h *section = firm->section; section < firm->section + 4; section++) { - if (section->address == 0) - break; - - if (section->type == FIRM_TYPE_ARM9) { - void* arm9section = (void*)firm + section->offset; - while (arm9section < arm9section + section->size) { - if (!memcmp(arm9section, "Process9", 8)) { // Process9 - ncch_h *ncch = (ncch_h*)(arm9section - sizeof(ncch_h)); - if (ncch->magic == NCCH_MAGIC) { - // Found Process9 - ncch_ex_h *p9exheader = (ncch_ex_h *)(ncch + 1); - *p9exefs = (exefs_h *)(p9exheader + 1); - process9->address = p9exheader->sci.textCodeSet.address; - process9->size = (*p9exefs)->fileHeaders[0].size; - process9->offset = (void*)((*p9exefs) + 1) - (void*)firm; - fprintf(BOTTOM_SCREEN, " Found Process9 for FIRM.\n"); - return 0; - } - } - ++arm9section; - } - } - } - fprintf(BOTTOM_SCREEN, " Couldn't find Process9?\n"); - return 1; +int +find_proc9(firm_h* firm, firm_section_h* process9, exefs_h** p9exefs) +{ + for (firm_section_h* section = firm->section; section < firm->section + 4; + section++) { + if (section->address == 0) + break; + + if (section->type == FIRM_TYPE_ARM9) { + void* arm9section = (void*)firm + section->offset; + while (arm9section < arm9section + section->size) { + if (!memcmp(arm9section, "Process9", 8)) { // Process9 + ncch_h* ncch = (ncch_h*)(arm9section - sizeof(ncch_h)); + if (ncch->magic == NCCH_MAGIC) { + // Found Process9 + ncch_ex_h* p9exheader = (ncch_ex_h*)(ncch + 1); + *p9exefs = (exefs_h*)(p9exheader + 1); + process9->address = p9exheader->sci.textCodeSet.address; + process9->size = (*p9exefs)->fileHeaders[0].size; + process9->offset = + (void*)((*p9exefs) + 1) - (void*)firm; + fprintf(BOTTOM_SCREEN, " Found Process9 for FIRM.\n"); + return 0; + } + } + ++arm9section; + } + } + } + fprintf(BOTTOM_SCREEN, " Couldn't find Process9?\n"); + return 1; } -int load_firms() { +int +load_firms() +{ fprintf(BOTTOM_SCREEN, "Loading FIRM...\n"); fprintf(BOTTOM_SCREEN, "Loading NATIVE_FIRM\n"); - if (load_firm(firm_loc, PATH_NATIVE_F, PATH_NATIVE_FIRMKEY, &firm_size, NATIVE_FIRM_TITLEID) != 0) + if (load_firm(firm_loc, PATH_NATIVE_F, PATH_NATIVE_FIRMKEY, &firm_size, + NATIVE_FIRM_TITLEID) != 0) return 1; find_proc9(firm_loc, &firm_proc9, &firm_p9_exefs); fprintf(BOTTOM_SCREEN, "Loading TWL_FIRM\n"); - if(load_firm(twl_firm_loc, PATH_TWL_F, PATH_TWL_FIRMKEY, &twl_firm_size, TWL_FIRM_TITLEID)) + if (load_firm(twl_firm_loc, PATH_TWL_F, PATH_TWL_FIRMKEY, &twl_firm_size, + TWL_FIRM_TITLEID)) fprintf(BOTTOM_SCREEN, " TWL_FIRM failed to load.\n"); - else - find_proc9(twl_firm_loc, &twl_firm_proc9, &twl_firm_p9_exefs); + else + find_proc9(twl_firm_loc, &twl_firm_proc9, &twl_firm_p9_exefs); fprintf(BOTTOM_SCREEN, "Loading AGB_FIRM\n"); - if(load_firm(agb_firm_loc, PATH_AGB_F, PATH_AGB_FIRMKEY, &agb_firm_size, AGB_FIRM_TITLEID)) + if (load_firm(agb_firm_loc, PATH_AGB_F, PATH_AGB_FIRMKEY, &agb_firm_size, + AGB_FIRM_TITLEID)) fprintf(BOTTOM_SCREEN, " AGB_FIRM failed to load.\n"); - else - find_proc9(agb_firm_loc, &agb_firm_proc9, &agb_firm_p9_exefs); + else + find_proc9(agb_firm_loc, &agb_firm_proc9, &agb_firm_p9_exefs); return 0; } -void boot_cfw() { +void +boot_cfw() +{ fprintf(BOTTOM_SCREEN, "Applying patches...\n"); if (patch_firm_all() != 0) return; diff --git a/source/firm/firm.h b/source/firm/firm.h index 73f6e57..84f421a 100644 --- a/source/firm/firm.h +++ b/source/firm/firm.h @@ -3,37 +3,39 @@ #include #include "headers.h" -enum consoles { - console_o3ds, - console_n3ds +enum consoles +{ + console_o3ds, + console_n3ds }; -struct firm_signature { - uint8_t sig[0x10]; - unsigned int version; - char version_string[16]; - enum consoles console; +struct firm_signature +{ + uint8_t sig[0x10]; + unsigned int version; + char version_string[16]; + enum consoles console; }; -extern firm_h *firm_loc; -extern struct firm_signature *current_firm; +extern firm_h* firm_loc; +extern struct firm_signature* current_firm; extern firm_section_h firm_proc9; -extern exefs_h *firm_p9_exefs; +extern exefs_h* firm_p9_exefs; -extern firm_h *twl_firm_loc; -extern struct firm_signature *current_twl_firm; +extern firm_h* twl_firm_loc; +extern struct firm_signature* current_twl_firm; extern firm_section_h twl_firm_proc9; -extern exefs_h *twl_firm_p9_exefs; +extern exefs_h* twl_firm_p9_exefs; -extern firm_h *agb_firm_loc; -extern struct firm_signature *current_agb_firm; +extern firm_h* agb_firm_loc; +extern struct firm_signature* current_agb_firm; extern firm_section_h agb_firm_proc9; -extern exefs_h *agb_firm_p9_exefs; +extern exefs_h* agb_firm_p9_exefs; -struct firm_signature *get_firm_info(firm_h *firm); +struct firm_signature* get_firm_info(firm_h* firm); void slot0x11key96_init(); -int load_firms(); +int load_firms(); void boot_firm(); void boot_cfw(); diff --git a/source/firm/headers.h b/source/firm/headers.h index 8ea3556..38a78bd 100644 --- a/source/firm/headers.h +++ b/source/firm/headers.h @@ -6,54 +6,60 @@ #include -#define FIRM_TYPE_ARM9 0 -#define FIRM_TYPE_ARM11 1 +#define FIRM_TYPE_ARM9 0 +#define FIRM_TYPE_ARM11 1 -#define MEDIA_UNITS 0x200 +#define MEDIA_UNITS 0x200 -#define NCCH_MAGIC (0x4843434E) -#define NCSD_MAGIC (0x4453434E) -#define FIRM_MAGIC (0x4D524946) -#define ARM9BIN_MAGIC (0x47704770) -#define LGY_ARM9BIN_MAGIC (0xB0862000) +#define NCCH_MAGIC (0x4843434E) +#define NCSD_MAGIC (0x4453434E) +#define FIRM_MAGIC (0x4D524946) +#define ARM9BIN_MAGIC (0x47704770) +#define LGY_ARM9BIN_MAGIC (0xB0862000) -struct memory_header { +struct memory_header +{ uint32_t location; uint32_t size; } memory_header_t; -typedef struct firm_section_h { +typedef struct firm_section_h +{ uint32_t offset; uint32_t address; uint32_t size; - uint32_t type; // Firmware Type ('0'=ARM9/'1'=ARM11) - uint8_t hash[0x20]; // SHA-256 Hash of Firmware Section -} firm_section_h; // 0x30 + uint32_t type; // Firmware Type ('0'=ARM9/'1'=ARM11) + uint8_t hash[0x20]; // SHA-256 Hash of Firmware Section +} firm_section_h; // 0x30 -typedef struct firm_h { - uint32_t magic; // FIRM +typedef struct firm_h +{ + uint32_t magic; // FIRM uint32_t reserved1; - uint32_t a11Entry; // ARM11 entry - uint32_t a9Entry; // ARM9 entry + uint32_t a11Entry; // ARM11 entry + uint32_t a9Entry; // ARM9 entry uint8_t reserved2[0x30]; firm_section_h section[4]; uint8_t sig[0x100]; } firm_h; // http://3dbrew.org/wiki/NCCH/Extended_Header -typedef struct code_set_info { +typedef struct code_set_info +{ uint32_t address; - uint32_t phy_region_size; // Physical region size (in page-multiples) - uint32_t size; // size in bytes -} code_set_info; // 0x0C + uint32_t phy_region_size; // Physical region size (in page-multiples) + uint32_t size; // size in bytes +} code_set_info; // 0x0C -typedef struct system_info { +typedef struct system_info +{ uint32_t saveDataSize[2]; uint32_t jumpID[2]; uint8_t reserved[0x30]; -} system_info; // 0x40 +} system_info; // 0x40 -typedef struct system_control_info { +typedef struct system_control_info +{ uint8_t appTitle[8]; char reserved1[5]; char flag; @@ -64,99 +70,123 @@ typedef struct system_control_info { char reserved2[4]; code_set_info dataCodeSet; uint32_t bssSize; - char depends[0x180]; // Dependency Module (Program ID) List 48*8 + char depends[0x180]; // Dependency Module (Program ID) List 48*8 system_info systemInfo; -} system_control_info; // 0x200 +} system_control_info; // 0x200 -typedef struct ncch_ex_h { +typedef struct ncch_ex_h +{ system_control_info sci; uint8_t aci[0x200]; uint8_t accessDescSig[0x100]; uint8_t ncchPubKey[0x100]; uint8_t aciLim[0x200]; -} ncch_ex_h; // 0x800 +} ncch_ex_h; // 0x800 // http://3dbrew.org/wiki/NCCH -typedef struct ncch_h { - uint8_t sig[0x100]; // RSA-2048 signature of the NCCH header, using SHA-256. - uint32_t magic; // NCCH - uint32_t contentSize; // Content size, in media units (1 media unit = 0x200 bytes) +typedef struct ncch_h +{ + uint8_t sig[0x100]; // RSA-2048 signature of the NCCH header, using SHA-256. + uint32_t magic; // NCCH + uint32_t contentSize; // Content size, in media units (1 media unit = 0x200 + // bytes) uint8_t partitionID[8]; uint8_t makerCode[2]; uint16_t version; uint8_t reserved1[4]; uint8_t programID[8]; uint8_t reserved2[0x10]; - uint8_t logoHash[0x20]; // Logo Region SHA-256 hash. (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11) + uint8_t logoHash[0x20]; // Logo Region SHA-256 hash. (For applications built + // with SDK 5+) (Supported from firmware: 5.0.0-11) uint8_t productCode[0x10]; - uint8_t exHeaderHash[0x20]; // Extended header SHA-256 hash (SHA256 of 2x Alignment Size, beginning at 0x0 of ExHeader) + uint8_t exHeaderHash[0x20]; // Extended header SHA-256 hash (SHA256 of 2x + // Alignment Size, beginning at 0x0 of ExHeader) uint32_t exHeaderSize; // Extended header size uint32_t reserved3; uint8_t flags[8]; - uint32_t plainOffset; // media unit - uint32_t plainSize; // media unit - uint32_t logoOffset; // media unit - uint32_t logoSize; // media unit - uint32_t exeFSOffset; // media unit - uint32_t exeFSSize; // media unit - uint32_t exeFSHashSize; // media unit ExeFS hash region size + uint32_t plainOffset; // media unit + uint32_t plainSize; // media unit + uint32_t logoOffset; // media unit + uint32_t logoSize; // media unit + uint32_t exeFSOffset; // media unit + uint32_t exeFSSize; // media unit + uint32_t exeFSHashSize; // media unit ExeFS hash region size uint32_t reserved4; - uint32_t romFSOffset; // media unit - uint32_t romFSSize; // media unit - uint32_t romFSHashSize; // media unit RomFS hash region size + uint32_t romFSOffset; // media unit + uint32_t romFSSize; // media unit + uint32_t romFSHashSize; // media unit RomFS hash region size uint32_t reserved5; - uint8_t exeFSHash[0x20]; // ExeFS superblock SHA-256 hash - (SHA-256 hash, starting at 0x0 of the ExeFS over the number of media units specified in the ExeFS hash region size) - uint8_t romFSHash[0x20]; // RomFS superblock SHA-256 hash - (SHA-256 hash, starting at 0x0 of the RomFS over the number of media units specified in the RomFS hash region size) -} ncch_h; // 0x200 - -#define NCCH_FLAG_NOCRYPTO 0x4 -#define NCCH_FLAG_7XCRYPTO 0x1 - -typedef struct cxi_h { + uint8_t exeFSHash[0x20]; // ExeFS superblock SHA-256 hash - (SHA-256 hash, + // starting at 0x0 of the ExeFS over the number of + // media units specified in the ExeFS hash region + // size) + uint8_t romFSHash[0x20]; // RomFS superblock SHA-256 hash - (SHA-256 hash, + // starting at 0x0 of the RomFS over the number of + // media units specified in the RomFS hash region + // size) +} ncch_h; // 0x200 + +#define NCCH_FLAG_NOCRYPTO 0x4 +#define NCCH_FLAG_7XCRYPTO 0x1 + +typedef struct cxi_h +{ ncch_h ncch; ncch_ex_h exheader; } cxi_h; -typedef struct exefs_file_h { +typedef struct exefs_file_h +{ uint8_t fname[0x8]; - uint32_t offset; // offset starts after exefs_h + uint32_t offset; // offset starts after exefs_h uint32_t size; -} exefs_file_h; // 0x10 +} exefs_file_h; // 0x10 -typedef struct exefs_file_hash { +typedef struct exefs_file_hash +{ uint8_t hash[0x20]; } exefs_file_hash; -typedef struct exefs_h { - exefs_file_h fileHeaders[10]; // File headers (10 headers maximum, 16 bytes each) +typedef struct exefs_h +{ + exefs_file_h + fileHeaders[10]; // File headers (10 headers maximum, 16 bytes each) uint8_t reserved[0x20]; - exefs_file_hash fileHashes[10]; // File hashes (10 hashes maximum, 32 bytes each, one for each header), SHA256 over entire file content + exefs_file_hash fileHashes[10]; // File hashes (10 hashes maximum, 32 bytes + // each, one for each header), SHA256 over + // entire file content } exefs_h; // 0x200 -typedef struct ncsd_partition_table { +typedef struct ncsd_partition_table +{ uint32_t offset; uint32_t size; } ncsd_partition_table; // http://3dbrew.org/wiki/NCSD -typedef struct ncsd_h { - uint8_t sig[0x100]; // RSA-2048 signature of the NCSD header, using SHA-256. - uint32_t magic; // NCSD - uint32_t size; // Size of the NCSD image, in media units (1 media unit = 0x200 bytes) +typedef struct ncsd_h +{ + uint8_t sig[0x100]; // RSA-2048 signature of the NCSD header, using SHA-256. + uint32_t magic; // NCSD + uint32_t size; // Size of the NCSD image, in media units (1 media unit = + // 0x200 bytes) uint8_t mediaID[8]; - uint8_t fsType[8]; // Partitions FS type (0=None, 1=Normal, 3=FIRM, 4=AGB_FIRM save) - uint8_t cryptType[8]; // Partitions crypt type - ncsd_partition_table ptable[8]; // Offset & Length partition table, in media units + uint8_t fsType[8]; // Partitions FS type (0=None, 1=Normal, 3=FIRM, + // 4=AGB_FIRM save) + uint8_t cryptType[8]; // Partitions crypt type + ncsd_partition_table + ptable[8]; // Offset & Length partition table, in media units uint8_t spec[0xA0]; } ncsd_h; -#define NCSD_PARTITION_EXE 0 -#define NCSD_PARTITION_MANUAL 1 -#define NCSD_PARTITION_DLP 2 -#define NCSD_PARTITION_N3DSUPDATE 6 -#define NCSD_PARTITION_O3DSUPDATE 7 +#define NCSD_PARTITION_EXE 0 +#define NCSD_PARTITION_MANUAL 1 +#define NCSD_PARTITION_DLP 2 +#define NCSD_PARTITION_N3DSUPDATE 6 +#define NCSD_PARTITION_O3DSUPDATE 7 -typedef struct arm9bin_h { +typedef struct arm9bin_h +{ uint8_t keyx[0x10]; uint8_t keyy[0x10]; uint8_t ctr[0x10]; @@ -184,9 +214,10 @@ typedef struct ticket_h uint16_t ticketTitleVersion; uint8_t reserved3[8]; uint8_t licenseType; - uint8_t ticketCommonKeyYIndex; //Ticket common keyY index, usually 0x1 for retail system titles. + uint8_t ticketCommonKeyYIndex; // Ticket common keyY index, usually 0x1 for + // retail system titles. uint8_t reserved4[0x2A]; - uint8_t unk[4]; // eShop Account ID? + uint8_t unk[4]; // eShop Account ID? uint8_t reserved5; uint8_t audit; uint8_t reserved6[0x42]; @@ -194,11 +225,11 @@ typedef struct ticket_h uint8_t contentIndex[0xAC]; } __attribute__((__packed__)) ticket_h; // 0x210 -#define SIG_TYPE_RSA4096_SHA1 0x010000 -#define SIG_TYPE_RSA2048_SHA1 0x010001 -#define SIG_TYPE_ECDSA_SHA1 0x010002 -#define SIG_TYPE_RSA4096_SHA256 0x010003 -#define SIG_TYPE_RSA2048_SHA256 0x010004 -#define SIG_TYPE_ECDSA_SHA256 0x010005 +#define SIG_TYPE_RSA4096_SHA1 0x010000 +#define SIG_TYPE_RSA2048_SHA1 0x010001 +#define SIG_TYPE_ECDSA_SHA1 0x010002 +#define SIG_TYPE_RSA4096_SHA256 0x010003 +#define SIG_TYPE_RSA2048_SHA256 0x010004 +#define SIG_TYPE_ECDSA_SHA256 0x010005 #endif diff --git a/source/firm/version.c b/source/firm/version.c index dfd9180..5ecdd48 100644 --- a/source/firm/version.c +++ b/source/firm/version.c @@ -3,99 +3,99 @@ // We use the firm's section 0's hash to identify the version struct firm_signature firm_signatures[] = { - { - .sig = {0xEE, 0xE2, 0x81, 0x2E, 0xB9, 0x10, 0x0D, 0x03, 0xFE, 0xA2, 0x3F, 0x44, 0xB5, 0x1C, 0xB3, 0x5E}, - .version = 0x1F, - .version_string = "4.1.0", - .console = console_o3ds - }, { - .sig = {0x8C, 0x29, 0xDA, 0x7B, 0xB5, 0x5F, 0xFE, 0x44, 0x1F, 0x66, 0x79, 0x70, 0x8E, 0xE4, 0x42, 0xE3}, - .version = 0x2A, - .version_string = "6.1.0", - .console = console_o3ds - }, { - .sig = {0x1D, 0x96, 0x80, 0xD9, 0x0A, 0xA9, 0xDB, 0xE8, 0x29, 0x77, 0xCB, 0x7D, 0x90, 0x55, 0xB7, 0xF9}, - .version = 0x30, - .version_string = "7.2.0", - .console = console_o3ds - }, { - .sig = {0x3B, 0x61, 0x2E, 0xBA, 0x42, 0xAE, 0x24, 0x46, 0xAD, 0x60, 0x2F, 0x7B, 0x52, 0x16, 0x82, 0x91}, - .version = 0x37, - .version_string = "8.0.0", - .console = console_o3ds - }, { - .sig = {0x3F, 0xBF, 0x14, 0x06, 0x33, 0x77, 0x82, 0xDE, 0xB2, 0x68, 0x83, 0x01, 0x6B, 0x1A, 0x71, 0x69}, - .version = 0x38, - .version_string = "9.0.0", - .console = console_o3ds - }, { - .sig = {0x5C, 0x6A, 0x51, 0xF3, 0x79, 0x4D, 0x21, 0x91, 0x0B, 0xBB, 0xFD, 0x17, 0x7B, 0x72, 0x6B, 0x59}, - .version = 0x49, - .version_string = "9.6.0", - .console = console_o3ds - }, { - .sig = {0xF5, 0x7E, 0xC3, 0x86, 0x1F, 0x8D, 0x8E, 0xFB, 0x44, 0x61, 0xF3, 0x16, 0x51, 0x0A, 0x57, 0x7D}, - .version = 0x50, - .version_string = "10.4.0", - .console = console_o3ds - }, { - .sig = {0xE9, 0xAD, 0x74, 0x9D, 0x46, 0x9C, 0x9C, 0xF4, 0x96, 0x9E, 0x1A, 0x7A, 0xDF, 0x40, 0x2A, 0x82}, - .version = 0x52, - .version_string = "11.0.0", - .console = console_o3ds - }, { - .sig = {0x31, 0xCC, 0x46, 0xCD, 0x61, 0x7A, 0xE7, 0x13, 0x7F, 0xE5, 0xFC, 0x20, 0x46, 0x91, 0x6A, 0xBB}, - .version = 0x04, - .version_string = "9.0.0", - .console = console_n3ds - }, { - .sig = {0x40, 0x35, 0x6C, 0x9A, 0x24, 0x36, 0x93, 0x7B, 0x76, 0xFE, 0x5D, 0xB1, 0x4D, 0x05, 0x06, 0x52}, - .version = 0x0F, - .version_string = "9.5.0", - .console = console_n3ds - }, { - .sig = {0x07, 0xFE, 0x9A, 0x62, 0x3F, 0xDE, 0x54, 0xC1, 0x9B, 0x06, 0x91, 0xD8, 0x4F, 0x44, 0x9C, 0x21}, - .version = 0x1B, - .version_string = "10.2.0", - .console = console_n3ds - }, { - .sig = {0x1A, 0x56, 0x5C, 0xFF, 0xC9, 0xCC, 0x62, 0xBB, 0x2B, 0xC2, 0x23, 0xB6, 0x4F, 0x48, 0xD1, 0xCC}, - .version = 0x1F, - .version_string = "10.4.0", - .console = console_n3ds - }, { - .sig = {0x52, 0x30, 0x0F, 0x55, 0xA2, 0x64, 0x4E, 0xFF, 0x96, 0x90, 0xF0, 0xE5, 0x6E, 0xC8, 0x2E, 0xB3}, - .version = 0x21, - .version_string = "11.0.0", - .console = console_n3ds - }, - { - .sig = {0xE8, 0xB8, 0x82, 0xF5, 0x8C, 0xC4, 0x1B, 0x24, 0x05, 0x60, 0x6D, 0xB8, 0x74, 0xF5, 0xE5, 0xDD}, - .version = 0x16, - .version_string = "6.2.0_TWL", - .console = console_o3ds - }, { - .sig = {0x0F, 0x05, 0xC5, 0xF3, 0x60, 0x83, 0x8B, 0x9D, 0xC8, 0x44, 0x3F, 0xB3, 0x06, 0x4D, 0x30, 0xC7}, - .version = 0x00, - .version_string = "9.0.0_TWL", - .console = console_n3ds - }, - { - .sig = {0x65, 0xB7, 0x55, 0x78, 0x97, 0xE6, 0x5C, 0xD6, 0x11, 0x74, 0x95, 0xDD, 0x61, 0xE8, 0x08, 0x40}, - .version = 0x0B, - .version_string = "6.0.0_AGB", - .console = console_o3ds - }, { - .sig = {0xAF, 0x81, 0xA1, 0xAB, 0xBA, 0xAC, 0xAC, 0xA7, 0x30, 0xE8, 0xD8, 0x74, 0x7C, 0x47, 0x1C, 0x5D}, - .version = 0x00, - .version_string = "9.0.0_AGB", - .console = console_n3ds - }, - {.version = 0xFF} // Terminate list + {.sig = { 0xEE, 0xE2, 0x81, 0x2E, 0xB9, 0x10, 0x0D, 0x03, 0xFE, 0xA2, 0x3F, + 0x44, 0xB5, 0x1C, 0xB3, 0x5E }, + .version = 0x1F, + .version_string = "4.1.0", + .console = console_o3ds }, + {.sig = { 0x8C, 0x29, 0xDA, 0x7B, 0xB5, 0x5F, 0xFE, 0x44, 0x1F, 0x66, 0x79, + 0x70, 0x8E, 0xE4, 0x42, 0xE3 }, + .version = 0x2A, + .version_string = "6.1.0", + .console = console_o3ds }, + {.sig = { 0x1D, 0x96, 0x80, 0xD9, 0x0A, 0xA9, 0xDB, 0xE8, 0x29, 0x77, 0xCB, + 0x7D, 0x90, 0x55, 0xB7, 0xF9 }, + .version = 0x30, + .version_string = "7.2.0", + .console = console_o3ds }, + {.sig = { 0x3B, 0x61, 0x2E, 0xBA, 0x42, 0xAE, 0x24, 0x46, 0xAD, 0x60, 0x2F, + 0x7B, 0x52, 0x16, 0x82, 0x91 }, + .version = 0x37, + .version_string = "8.0.0", + .console = console_o3ds }, + {.sig = { 0x3F, 0xBF, 0x14, 0x06, 0x33, 0x77, 0x82, 0xDE, 0xB2, 0x68, 0x83, + 0x01, 0x6B, 0x1A, 0x71, 0x69 }, + .version = 0x38, + .version_string = "9.0.0", + .console = console_o3ds }, + {.sig = { 0x5C, 0x6A, 0x51, 0xF3, 0x79, 0x4D, 0x21, 0x91, 0x0B, 0xBB, 0xFD, + 0x17, 0x7B, 0x72, 0x6B, 0x59 }, + .version = 0x49, + .version_string = "9.6.0", + .console = console_o3ds }, + {.sig = { 0xF5, 0x7E, 0xC3, 0x86, 0x1F, 0x8D, 0x8E, 0xFB, 0x44, 0x61, 0xF3, + 0x16, 0x51, 0x0A, 0x57, 0x7D }, + .version = 0x50, + .version_string = "10.4.0", + .console = console_o3ds }, + {.sig = { 0xE9, 0xAD, 0x74, 0x9D, 0x46, 0x9C, 0x9C, 0xF4, 0x96, 0x9E, 0x1A, + 0x7A, 0xDF, 0x40, 0x2A, 0x82 }, + .version = 0x52, + .version_string = "11.0.0", + .console = console_o3ds }, + {.sig = { 0x31, 0xCC, 0x46, 0xCD, 0x61, 0x7A, 0xE7, 0x13, 0x7F, 0xE5, 0xFC, + 0x20, 0x46, 0x91, 0x6A, 0xBB }, + .version = 0x04, + .version_string = "9.0.0", + .console = console_n3ds }, + {.sig = { 0x40, 0x35, 0x6C, 0x9A, 0x24, 0x36, 0x93, 0x7B, 0x76, 0xFE, 0x5D, + 0xB1, 0x4D, 0x05, 0x06, 0x52 }, + .version = 0x0F, + .version_string = "9.5.0", + .console = console_n3ds }, + {.sig = { 0x07, 0xFE, 0x9A, 0x62, 0x3F, 0xDE, 0x54, 0xC1, 0x9B, 0x06, 0x91, + 0xD8, 0x4F, 0x44, 0x9C, 0x21 }, + .version = 0x1B, + .version_string = "10.2.0", + .console = console_n3ds }, + {.sig = { 0x1A, 0x56, 0x5C, 0xFF, 0xC9, 0xCC, 0x62, 0xBB, 0x2B, 0xC2, 0x23, + 0xB6, 0x4F, 0x48, 0xD1, 0xCC }, + .version = 0x1F, + .version_string = "10.4.0", + .console = console_n3ds }, + {.sig = { 0x52, 0x30, 0x0F, 0x55, 0xA2, 0x64, 0x4E, 0xFF, 0x96, 0x90, 0xF0, + 0xE5, 0x6E, 0xC8, 0x2E, 0xB3 }, + .version = 0x21, + .version_string = "11.0.0", + .console = console_n3ds }, + {.sig = { 0xE8, 0xB8, 0x82, 0xF5, 0x8C, 0xC4, 0x1B, 0x24, 0x05, 0x60, 0x6D, + 0xB8, 0x74, 0xF5, 0xE5, 0xDD }, + .version = 0x16, + .version_string = "6.2.0_TWL", + .console = console_o3ds }, + {.sig = { 0x0F, 0x05, 0xC5, 0xF3, 0x60, 0x83, 0x8B, 0x9D, 0xC8, 0x44, 0x3F, + 0xB3, 0x06, 0x4D, 0x30, 0xC7 }, + .version = 0x00, + .version_string = "9.0.0_TWL", + .console = console_n3ds }, + {.sig = { 0x65, 0xB7, 0x55, 0x78, 0x97, 0xE6, 0x5C, 0xD6, 0x11, 0x74, 0x95, + 0xDD, 0x61, 0xE8, 0x08, 0x40 }, + .version = 0x0B, + .version_string = "6.0.0_AGB", + .console = console_o3ds }, + {.sig = { 0xAF, 0x81, 0xA1, 0xAB, 0xBA, 0xAC, 0xAC, 0xA7, 0x30, 0xE8, 0xD8, + 0x74, 0x7C, 0x47, 0x1C, 0x5D }, + .version = 0x00, + .version_string = "9.0.0_AGB", + .console = console_n3ds }, + {.version = 0xFF } // Terminate list }; -struct firm_signature *get_firm_info(firm_h *firm) { - for (struct firm_signature *signature = firm_signatures; signature->version != 0xFF; signature++) { +struct firm_signature* +get_firm_info(firm_h* firm) +{ + for (struct firm_signature* signature = firm_signatures; + signature->version != 0xFF; signature++) { if (memcmp(signature->sig, firm->section[0].hash, 0x10) == 0) { return signature; } diff --git a/source/i2c.c b/source/i2c.c index c00f19b..d371c14 100644 --- a/source/i2c.c +++ b/source/i2c.c @@ -2,19 +2,24 @@ //----------------------------------------------------------------------------- -static const struct { uint8_t bus_id, reg_addr; } dev_data[] = { - {0, 0x4A}, {0, 0x7A}, {0, 0x78}, - {1, 0x4A}, {1, 0x78}, {1, 0x2C}, - {1, 0x2E}, {1, 0x40}, {1, 0x44}, - {2, 0xD6}, {2, 0xD0}, {2, 0xD2}, - {2, 0xA4}, {2, 0x9A}, {2, 0xA0}, +static const struct +{ + uint8_t bus_id, reg_addr; +} dev_data[] = { + { 0, 0x4A }, { 0, 0x7A }, { 0, 0x78 }, { 1, 0x4A }, { 1, 0x78 }, + { 1, 0x2C }, { 1, 0x2E }, { 1, 0x40 }, { 1, 0x44 }, { 2, 0xD6 }, + { 2, 0xD0 }, { 2, 0xD2 }, { 2, 0xA4 }, { 2, 0x9A }, { 2, 0xA0 }, }; -uint8_t i2cGetDeviceBusId(uint8_t device_id) { +uint8_t +i2cGetDeviceBusId(uint8_t device_id) +{ return dev_data[device_id].bus_id; } -uint8_t i2cGetDeviceRegAddr(uint8_t device_id) { +uint8_t +i2cGetDeviceRegAddr(uint8_t device_id) +{ return dev_data[device_id].reg_addr; } @@ -26,7 +31,9 @@ static volatile uint8_t* const reg_data_addrs[] = { (volatile uint8_t*)(I2C3_REG_OFF + I2C_REG_DATA), }; -volatile uint8_t* i2cGetDataReg(uint8_t bus_id) { +volatile uint8_t* +i2cGetDataReg(uint8_t bus_id) +{ return reg_data_addrs[bus_id]; } @@ -38,22 +45,31 @@ static volatile uint8_t* const reg_cnt_addrs[] = { (volatile uint8_t*)(I2C3_REG_OFF + I2C_REG_CNT), }; -volatile uint8_t* i2cGetCntReg(uint8_t bus_id) { +volatile uint8_t* +i2cGetCntReg(uint8_t bus_id) +{ return reg_cnt_addrs[bus_id]; } //----------------------------------------------------------------------------- -void i2cWaitBusy(uint8_t bus_id) { - while (*i2cGetCntReg(bus_id) & 0x80); +void +i2cWaitBusy(uint8_t bus_id) +{ + while (*i2cGetCntReg(bus_id) & 0x80) + ; } -int i2cGetResult(uint8_t bus_id) { +int +i2cGetResult(uint8_t bus_id) +{ i2cWaitBusy(bus_id); return (*i2cGetCntReg(bus_id) >> 4) & 1; } -void i2cStop(uint8_t bus_id, uint8_t arg0) { +void +i2cStop(uint8_t bus_id, uint8_t arg0) +{ *i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0; i2cWaitBusy(bus_id); *i2cGetCntReg(bus_id) = 0xC5; @@ -61,14 +77,18 @@ void i2cStop(uint8_t bus_id, uint8_t arg0) { //----------------------------------------------------------------------------- -int i2cSelectDevice(uint8_t bus_id, uint8_t dev_reg) { +int +i2cSelectDevice(uint8_t bus_id, uint8_t dev_reg) +{ i2cWaitBusy(bus_id); *i2cGetDataReg(bus_id) = dev_reg; *i2cGetCntReg(bus_id) = 0xC2; return i2cGetResult(bus_id); } -int i2cSelectRegister(uint8_t bus_id, uint8_t reg) { +int +i2cSelectRegister(uint8_t bus_id, uint8_t reg) +{ i2cWaitBusy(bus_id); *i2cGetDataReg(bus_id) = reg; *i2cGetCntReg(bus_id) = 0xC0; @@ -77,12 +97,15 @@ int i2cSelectRegister(uint8_t bus_id, uint8_t reg) { //----------------------------------------------------------------------------- -uint8_t i2cReadRegister(uint8_t dev_id, uint8_t reg) { +uint8_t +i2cReadRegister(uint8_t dev_id, uint8_t reg) +{ uint8_t bus_id = i2cGetDeviceBusId(dev_id); uint8_t dev_addr = i2cGetDeviceRegAddr(dev_id); for (size_t i = 0; i < 8; i++) { - if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { + if (i2cSelectDevice(bus_id, dev_addr) && + i2cSelectRegister(bus_id, reg)) { if (i2cSelectDevice(bus_id, dev_addr | 1)) { i2cWaitBusy(bus_id); i2cStop(bus_id, 1); @@ -96,15 +119,17 @@ uint8_t i2cReadRegister(uint8_t dev_id, uint8_t reg) { return 0xff; } -int i2cReadRegisterBuffer(unsigned int dev_id, int reg, uint8_t* buffer, size_t buf_size) { +int +i2cReadRegisterBuffer(unsigned int dev_id, int reg, uint8_t* buffer, + size_t buf_size) +{ uint8_t bus_id = i2cGetDeviceBusId(dev_id); uint8_t dev_addr = i2cGetDeviceRegAddr(dev_id); size_t j = 0; - while (!i2cSelectDevice(bus_id, dev_addr) - || !i2cSelectRegister(bus_id, reg) - || !i2cSelectDevice(bus_id, dev_addr | 1)) - { + while (!i2cSelectDevice(bus_id, dev_addr) || + !i2cSelectRegister(bus_id, reg) || + !i2cSelectDevice(bus_id, dev_addr | 1)) { i2cWaitBusy(bus_id); *i2cGetCntReg(bus_id) = 0xC5; i2cWaitBusy(bus_id); @@ -128,12 +153,15 @@ int i2cReadRegisterBuffer(unsigned int dev_id, int reg, uint8_t* buffer, size_t return 1; } -int i2cWriteRegister(uint8_t dev_id, uint8_t reg, uint8_t data) { +int +i2cWriteRegister(uint8_t dev_id, uint8_t reg, uint8_t data) +{ uint8_t bus_id = i2cGetDeviceBusId(dev_id); uint8_t dev_addr = i2cGetDeviceRegAddr(dev_id); for (int i = 0; i < 8; i++) { - if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { + if (i2cSelectDevice(bus_id, dev_addr) && + i2cSelectRegister(bus_id, reg)) { i2cWaitBusy(bus_id); *i2cGetDataReg(bus_id) = data; *i2cGetCntReg(bus_id) = 0xC1; diff --git a/source/i2c.h b/source/i2c.h index ebde4ac..6aaceac 100644 --- a/source/i2c.h +++ b/source/i2c.h @@ -6,14 +6,14 @@ #define I2C2_REG_OFF 0x10144000 #define I2C3_REG_OFF 0x10148000 -#define I2C_REG_DATA 0 -#define I2C_REG_CNT 1 +#define I2C_REG_DATA 0 +#define I2C_REG_CNT 1 #define I2C_REG_CNTEX 2 -#define I2C_REG_SCL 4 +#define I2C_REG_SCL 4 -#define I2C_DEV_MCU 3 +#define I2C_DEV_MCU 3 #define I2C_DEV_GYRO 10 -#define I2C_DEV_IR 13 +#define I2C_DEV_IR 13 uint8_t i2cGetDeviceBusId(uint8_t device_id); uint8_t i2cGetDeviceRegAddr(uint8_t device_id); @@ -32,4 +32,5 @@ int i2cSelectRegister(uint8_t bus_id, uint8_t reg); uint8_t i2cReadRegister(uint8_t dev_id, uint8_t reg); int i2cWriteRegister(uint8_t dev_id, uint8_t reg, uint8_t data); -int i2cReadRegisterBuffer(unsigned int dev_id, int reg, uint8_t* buffer, size_t buf_size); +int i2cReadRegisterBuffer(unsigned int dev_id, int reg, uint8_t* buffer, + size_t buf_size); diff --git a/source/input.h b/source/input.h index c08a0ef..bdbd9e3 100644 --- a/source/input.h +++ b/source/input.h @@ -1,19 +1,18 @@ -#define BUTTON_A (1 << 0) -#define BUTTON_B (1 << 1) -#define BUTTON_SEL (1 << 2) -#define BUTTON_STA (1 << 3) -#define BUTTON_RIGHT (1 << 4) -#define BUTTON_LEFT (1 << 5) -#define BUTTON_UP (1 << 6) -#define BUTTON_DOWN (1 << 7) -#define BUTTON_R (1 << 8) -#define BUTTON_L (1 << 9) -#define BUTTON_X (1 << 10) -#define BUTTON_Y (1 << 11) +#define BUTTON_A (1 << 0) +#define BUTTON_B (1 << 1) +#define BUTTON_SEL (1 << 2) +#define BUTTON_STA (1 << 3) +#define BUTTON_RIGHT (1 << 4) +#define BUTTON_LEFT (1 << 5) +#define BUTTON_UP (1 << 6) +#define BUTTON_DOWN (1 << 7) +#define BUTTON_R (1 << 8) +#define BUTTON_L (1 << 9) +#define BUTTON_X (1 << 10) +#define BUTTON_Y (1 << 11) /* FIXME - I had ZR and ZL in, but they don't appear to behave rationally without some initialization. */ -#define BUTTON_ANY 0xFFF - -#define HID_PAD ((*(volatile uint32_t *)0x10146000) ^ BUTTON_ANY) +#define BUTTON_ANY 0xFFF +#define HID_PAD ((*(volatile uint32_t*)0x10146000) ^ BUTTON_ANY) diff --git a/source/linker.c b/source/linker.c index af13c19..219c435 100644 --- a/source/linker.c +++ b/source/linker.c @@ -12,82 +12,90 @@ // flexibility unlike a 'patch format'. extern exefs_h* firm_p9_exefs; -exefs_h* get_firm_proc9_exefs() { - return firm_p9_exefs; +exefs_h* +get_firm_proc9_exefs() +{ + return firm_p9_exefs; } extern exefs_h* twl_firm_p9_exefs; -exefs_h* get_twl_proc9_exefs() { - return twl_firm_p9_exefs; +exefs_h* +get_twl_proc9_exefs() +{ + return twl_firm_p9_exefs; } extern exefs_h* agb_firm_p9_exefs; -exefs_h* get_agb_proc9_exefs() { - return agb_firm_p9_exefs; +exefs_h* +get_agb_proc9_exefs() +{ + return agb_firm_p9_exefs; } -int execp(char* path) { - int basename = 0; - for(basename=strlen(path); basename > 0; basename--) - if (path[basename] == '/') - break; - basename++; +int +execp(char* path) +{ + int basename = 0; + for (basename = strlen(path); basename > 0; basename--) + if (path[basename] == '/') + break; + basename++; - fprintf(stderr, "Exec: %s\n", &path[basename]); + fprintf(stderr, "Exec: %s\n", &path[basename]); - struct system_patch patch; + struct system_patch patch; - // Load patch from path. - FILE* f = fopen(path, "r"); - fread(&patch, 1, sizeof(patch), f); + // Load patch from path. + FILE* f = fopen(path, "r"); + fread(&patch, 1, sizeof(patch), f); - fprintf(stderr, " [h]"); + fprintf(stderr, " [h]"); - fread((uint8_t*)FCRAM_PATCHBIN_EXEC_LOC, 1, patch.patch_size, f); + fread((uint8_t*)FCRAM_PATCHBIN_EXEC_LOC, 1, patch.patch_size, f); - fprintf(stderr, "[x]"); + fprintf(stderr, "[x]"); - fclose(f); + fclose(f); - fprintf(stderr, "[s]"); + fprintf(stderr, "[s]"); - uint32_t* link_table = (uint32_t*)(FCRAM_PATCHBIN_EXEC_LOC+4); + uint32_t* link_table = (uint32_t*)(FCRAM_PATCHBIN_EXEC_LOC + 4); - fprintf(stderr, "[r]"); + fprintf(stderr, "[r]"); - // 0 - magic + // 0 - magic - // memory.c - link_table[2] = (uint32_t)strlen; - link_table[4] = (uint32_t)isprint; - link_table[6] = (uint32_t)memcpy; - link_table[8] = (uint32_t)memmove; - link_table[10] = (uint32_t)memset; - link_table[12] = (uint32_t)memcmp; - link_table[14] = (uint32_t)strncpy; - link_table[16] = (uint32_t)strncmp; - link_table[18] = (uint32_t)atoi; - link_table[20] = (uint32_t)memfind; + // memory.c + link_table[2] = (uint32_t)strlen; + link_table[4] = (uint32_t)isprint; + link_table[6] = (uint32_t)memcpy; + link_table[8] = (uint32_t)memmove; + link_table[10] = (uint32_t)memset; + link_table[12] = (uint32_t)memcmp; + link_table[14] = (uint32_t)strncpy; + link_table[16] = (uint32_t)strncmp; + link_table[18] = (uint32_t)atoi; + link_table[20] = (uint32_t)memfind; - // draw.c - link_table[22] = (uint32_t)putc; - link_table[24] = (uint32_t)puts; - link_table[26] = (uint32_t)fprintf; + // draw.c + link_table[22] = (uint32_t)putc; + link_table[24] = (uint32_t)puts; + link_table[26] = (uint32_t)fprintf; - // Get functions - link_table[28] = (uint32_t)get_firm_proc9_exefs; + // Get functions + link_table[28] = (uint32_t)get_firm_proc9_exefs; - link_table[30] = (uint32_t)get_agb_proc9_exefs; + link_table[30] = (uint32_t)get_agb_proc9_exefs; - link_table[32] = (uint32_t)get_twl_proc9_exefs; + link_table[32] = (uint32_t)get_twl_proc9_exefs; - fprintf(stderr, "[b]\n"); + fprintf(stderr, "[b]\n"); - int (*patch_loc)() = (void*)FCRAM_PATCHBIN_EXEC_LOC ; + int (*patch_loc)() = (void*)FCRAM_PATCHBIN_EXEC_LOC; - int ret = (*patch_loc)(); + int ret = (*patch_loc)(); - fprintf(stderr, " Exit: %d\n", ret); + fprintf(stderr, " Exit: %d\n", ret); - return ret; + return ret; } diff --git a/source/main.c b/source/main.c index 28c3e41..d0a35aa 100644 --- a/source/main.c +++ b/source/main.c @@ -8,35 +8,38 @@ int menu_handler(); int doing_autoboot = 0; void shut_up(); -int main() { +int +main() +{ if (fmount()) { // Failed to mount SD. Bomb out. - fprintf(BOTTOM_SCREEN, "%pFailed to mount SD card.\n", COLOR(RED, BLACK)); + fprintf(BOTTOM_SCREEN, "%pFailed to mount SD card.\n", + COLOR(RED, BLACK)); } load_config(); // Load configuration. - // Autoboot. Non-standard code path. - if (config.options[OPTION_AUTOBOOT] && !(HID_PAD & BUTTON_R)) { - if (config.options[OPTION_SILENCE]) - shut_up(); - load_firms(); - doing_autoboot = 1; - boot_cfw(); // Just boot shit. - } + // Autoboot. Non-standard code path. + if (config.options[OPTION_AUTOBOOT] && !(HID_PAD & BUTTON_R)) { + if (config.options[OPTION_SILENCE]) + shut_up(); + load_firms(); + doing_autoboot = 1; + boot_cfw(); // Just boot shit. + } int in_menu = 1; load_firms(); - while(in_menu) { + while (in_menu) { in_menu = menu_handler(); } - fprintf(BOTTOM_SCREEN, "Booting CFW\n"); + fprintf(BOTTOM_SCREEN, "Booting CFW\n"); - save_config(); // Save config file. + save_config(); // Save config file. - boot_cfw(); + boot_cfw(); // Under ideal conditions, we never get here. } diff --git a/source/menu.c b/source/menu.c index c5261f4..a48f735 100644 --- a/source/menu.c +++ b/source/menu.c @@ -1,52 +1,54 @@ #include "common.h" #include "firm/firm.h" #include "firm/headers.h" -#define MENU_MAIN 1 +#define MENU_MAIN 1 -#define MENU_OPTIONS 2 -#define MENU_PATCHES 3 -#define MENU_INFO 4 -#define MENU_HELP 5 -#define MENU_RESET 6 -#define MENU_POWER 7 -#define MENU_BOOTME 8 +#define MENU_OPTIONS 2 +#define MENU_PATCHES 3 +#define MENU_INFO 4 +#define MENU_HELP 5 +#define MENU_RESET 6 +#define MENU_POWER 7 +#define MENU_BOOTME 8 static struct options_s options[] = { - { 0, "Signature Patch", boolean_val, 0, 0 }, - { 1, "FIRM Protection", boolean_val, 0, 0 }, - { 2, "SysModule Replacement", boolean_val, 0, 0 }, - { 3, "Service Replacement", boolean_val, 0, 0 }, - { 4, "ARM9 Thread", boolean_val, 0, 0 }, + { 0, "Signature Patch", boolean_val, 0, 0 }, + { 1, "FIRM Protection", boolean_val, 0, 0 }, + { 2, "SysModule Replacement", boolean_val, 0, 0 }, + { 3, "Service Replacement", boolean_val, 0, 0 }, + { 4, "ARM9 Thread", boolean_val, 0, 0 }, - { 5, "Autoboot", boolean_val, 0, 0 }, - { 6, "Silence w/ Autoboot", boolean_val, 0, 0 }, - { 7, "Step through with button", boolean_val, 0, 0 }, + { 5, "Autoboot", boolean_val, 0, 0 }, + { 6, "Silence w/ Autoboot", boolean_val, 0, 0 }, + { 7, "Step through with button", boolean_val, 0, 0 }, - { 8, "Don't draw background color", boolean_val, 0, 0 }, - { 9, "Preserve framebuffer data", boolean_val, 0, 0 }, + { 8, "Don't draw background color", boolean_val, 0, 0 }, + { 9, "Preserve framebuffer data", boolean_val, 0, 0 }, - { 10, "Hide Help from menu", boolean_val, 0, 0 }, + { 10, "Hide Help from menu", boolean_val, 0, 0 }, - { 11, "Loader: CPU L2 enable", boolean_val, 0, 0 }, - { 12, "Loader: CPU 800Mhz mode", boolean_val, 0, 0 }, - { 13, "Loader: Language Emulation", boolean_val, 0, 0 }, + { 11, "Loader: CPU L2 enable", boolean_val, 0, 0 }, + { 12, "Loader: CPU 800Mhz mode", boolean_val, 0, 0 }, + { 13, "Loader: Language Emulation", boolean_val, 0, 0 }, - { 14, "Svc: Force replace allocated", boolean_val, 0, 0 }, + { 14, "Svc: Force replace allocated", boolean_val, 0, 0 }, - { 15, "No dependency tracking", boolean_val, 0, 0 }, - { 16, "Allow unsafe options", boolean_val, 0, 0 }, + { 15, "No dependency tracking", boolean_val, 0, 0 }, + { 16, "Allow unsafe options", boolean_val, 0, 0 }, - { -1, "", 0, 0, 0}, + { -1, "", 0, 0, 0 }, }; static int cursor_y = 0; static int which_menu = 1; static int need_redraw = 1; -uint32_t wait_key() { +uint32_t +wait_key() +{ uint32_t get = 0; - while(get == 0) { - if(HID_PAD & BUTTON_UP) + while (get == 0) { + if (HID_PAD & BUTTON_UP) get = BUTTON_UP; else if (HID_PAD & BUTTON_DOWN) get = BUTTON_DOWN; @@ -59,64 +61,77 @@ uint32_t wait_key() { else if (HID_PAD & BUTTON_B) get = BUTTON_B; } - while(HID_PAD&get); + while (HID_PAD & get) + ; return get; } -void header(char* append) { +void +header(char* append) +{ fprintf(stdout, "\x1b[33;40m[.corbenik//%s] %s\x1b[0m\n", VERSION, append); } -int menu_patches() { return MENU_MAIN; } +int +menu_patches() +{ + return MENU_MAIN; +} -int menu_options() { +int +menu_options() +{ set_cursor(TOP_SCREEN, 0, 0); header("A:Enter B:Back DPAD:Nav"); - int i = 0; - while(options[i].index != -1) { // -1 Sentinel. + int i = 0; + while (options[i].index != -1) { // -1 Sentinel. if (cursor_y == i) fprintf(TOP_SCREEN, "\x1b[32m>>\x1b[0m "); else fprintf(TOP_SCREEN, " "); if (need_redraw) - fprintf(TOP_SCREEN, "[%c] %s\n", (config.options[options[i].index] ? 'X' : ' '), options[i].name); - else { - // Yes, this is weird. printf does a large number of extra things we don't - // want computed at the moment; this is faster. - putc(TOP_SCREEN, '['); - putc(TOP_SCREEN, (config.options[options[i].index] ? 'X' : ' ')); - putc(TOP_SCREEN, ']'); - putc(TOP_SCREEN, '\n'); - } - ++i; + fprintf(TOP_SCREEN, "[%c] %s\n", + (config.options[options[i].index] ? 'X' : ' '), + options[i].name); + else { + // Yes, this is weird. printf does a large number of extra things we + // don't + // want computed at the moment; this is faster. + putc(TOP_SCREEN, '['); + putc(TOP_SCREEN, (config.options[options[i].index] ? 'X' : ' ')); + putc(TOP_SCREEN, ']'); + putc(TOP_SCREEN, '\n'); + } + ++i; } - need_redraw = 0; + need_redraw = 0; uint32_t key = wait_key(); - switch(key) { + switch (key) { case BUTTON_UP: cursor_y -= 1; - if (cursor_y < 0) - cursor_y = 0; + if (cursor_y < 0) + cursor_y = 0; break; case BUTTON_DOWN: cursor_y += 1; - if (options[cursor_y].index == -1) - cursor_y -= 1; + if (options[cursor_y].index == -1) + cursor_y -= 1; break; case BUTTON_A: // TODO - Value options - config.options[options[cursor_y].index] = !config.options[options[cursor_y].index]; + config.options[options[cursor_y].index] = + !config.options[options[cursor_y].index]; break; case BUTTON_B: - need_redraw = 1; - clear_screen(TOP_SCREEN); - cursor_y = 0; + need_redraw = 1; + clear_screen(TOP_SCREEN); + cursor_y = 0; return MENU_MAIN; break; } @@ -124,155 +139,162 @@ int menu_options() { return 0; } -int menu_info() { +int +menu_info() +{ clear_screen(TOP_SCREEN); set_cursor(TOP_SCREEN, 0, 0); header("Any:Back"); - struct firm_signature *native = get_firm_info(firm_loc); - struct firm_signature *agb = get_firm_info(agb_firm_loc); - struct firm_signature *twl = get_firm_info(twl_firm_loc); - - fprintf(stdout, "\nNATIVE_FIRM / Firmware:\n" - " Version: %s (%x)\n" - "AGB_FIRM / GBA Firmware:\n" - " Version: %s (%x)\n" - "TWL_FIRM / DSi Firmware:\n" - " Version: %s (%x)\n", - native->version_string, native->version, - agb->version_string, agb->version, - twl->version_string, twl->version); + struct firm_signature* native = get_firm_info(firm_loc); + struct firm_signature* agb = get_firm_info(agb_firm_loc); + struct firm_signature* twl = get_firm_info(twl_firm_loc); + + fprintf(stdout, "\nNATIVE_FIRM / Firmware:\n" + " Version: %s (%x)\n" + "AGB_FIRM / GBA Firmware:\n" + " Version: %s (%x)\n" + "TWL_FIRM / DSi Firmware:\n" + " Version: %s (%x)\n", + native->version_string, native->version, agb->version_string, + agb->version, twl->version_string, twl->version); while (1) { if (wait_key() & BUTTON_ANY) break; } - need_redraw = 1; + need_redraw = 1; clear_screen(TOP_SCREEN); return MENU_MAIN; } -int menu_help() { +int +menu_help() +{ clear_screen(TOP_SCREEN); set_cursor(TOP_SCREEN, 0, 0); header("Any:Back"); - fprintf(stdout, "\nCorbenik is a 3DS firmware patching tool;\n" - " commonly known as a CFW. It seeks to address\n" - " some faults in other CFWs and is generally\n" - " just another choice for users - but primarily\n" - " is intended for developers.\n" - "\n" - "Credits to people who've helped me put this\n" - " together either by code or helpfulness:\n" - " @mid-kid, @Wolfvak, @Reisyukaku, @AuroraWright\n" - " @d0k3, @TuxSH, and others\n" - "\n" - "[PROTECT BREAK] DATA DRAIN: OK\n" - "\n" - " \n" - "\n"); + fprintf(stdout, "\nCorbenik is a 3DS firmware patching tool;\n" + " commonly known as a CFW. It seeks to address\n" + " some faults in other CFWs and is generally\n" + " just another choice for users - but primarily\n" + " is intended for developers.\n" + "\n" + "Credits to people who've helped me put this\n" + " together either by code or helpfulness:\n" + " @mid-kid, @Wolfvak, @Reisyukaku, @AuroraWright\n" + " @d0k3, @TuxSH, and others\n" + "\n" + "[PROTECT BREAK] DATA DRAIN: OK\n" + "\n" + " \n" + "\n"); while (1) { if (wait_key() & BUTTON_ANY) break; } - need_redraw = 1; + need_redraw = 1; clear_screen(TOP_SCREEN); return MENU_MAIN; } -int menu_reset() { +int +menu_reset() +{ fumount(); // Unmount SD. // Reboot. fprintf(BOTTOM_SCREEN, "Resetting system.\n"); i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); - while(1); + while (1) + ; } -int menu_poweroff() { +int +menu_poweroff() +{ fumount(); // Unmount SD. // Reboot. fprintf(BOTTOM_SCREEN, "Powering off system.\n"); i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0); - while(1); + while (1) + ; } -int menu_main() { +int +menu_main() +{ set_cursor(TOP_SCREEN, 0, 0); - const char *list[] = { - "Options", - "Patches", - "Info", - "Help/Readme", - "Reset", - "Power off", - "Boot firmware" - }; + const char* list[] = { "Options", "Patches", "Info", + "Help/Readme", "Reset", "Power off", + "Boot firmware" }; int menu_max = 7; header("A:Enter DPAD:Nav"); - for(int i=0; i < menu_max; i++) { - if (!(i+2 == MENU_HELP && config.options[OPTION_READ_ME])) { - if (cursor_y == i) - fprintf(TOP_SCREEN, "\x1b[32m>>\x1b[0m "); - else - fprintf(TOP_SCREEN, " "); - - if (need_redraw) - fprintf(TOP_SCREEN, "%s\n", list[i]); - else - putc(TOP_SCREEN, '\n'); - } + for (int i = 0; i < menu_max; i++) { + if (!(i + 2 == MENU_HELP && config.options[OPTION_READ_ME])) { + if (cursor_y == i) + fprintf(TOP_SCREEN, "\x1b[32m>>\x1b[0m "); + else + fprintf(TOP_SCREEN, " "); + + if (need_redraw) + fprintf(TOP_SCREEN, "%s\n", list[i]); + else + putc(TOP_SCREEN, '\n'); + } } - need_redraw = 0; + need_redraw = 0; uint32_t key = wait_key(); - int ret = cursor_y+2; + int ret = cursor_y + 2; - switch(key) { + switch (key) { case BUTTON_UP: cursor_y -= 1; - if (config.options[OPTION_READ_ME] && cursor_y+2 == MENU_HELP) - cursor_y -= 1; // Disable help. + if (config.options[OPTION_READ_ME] && cursor_y + 2 == MENU_HELP) + cursor_y -= 1; // Disable help. break; case BUTTON_DOWN: cursor_y += 1; - if (config.options[OPTION_READ_ME] && cursor_y+2 == MENU_HELP) - cursor_y += 1; // Disable help. + if (config.options[OPTION_READ_ME] && cursor_y + 2 == MENU_HELP) + cursor_y += 1; // Disable help. break; case BUTTON_A: - need_redraw = 1; - cursor_y = 0; + need_redraw = 1; + cursor_y = 0; if (ret == MENU_BOOTME) - return MENU_BOOTME; // Boot meh, damnit! + return MENU_BOOTME; // Boot meh, damnit! return ret; } // Loop around the cursor. if (cursor_y < 0) - cursor_y = menu_max -1; + cursor_y = menu_max - 1; if (cursor_y > menu_max - 1) cursor_y = 0; return 0; } -int menu_handler() { +int +menu_handler() +{ int to_menu = 0; - switch(which_menu) { + switch (which_menu) { case MENU_MAIN: to_menu = menu_main(); break; @@ -294,9 +316,9 @@ int menu_handler() { menu_reset(); case MENU_POWER: menu_poweroff(); - default: - fprintf(stderr, "Attempt to enter wrong menu!\n"); - to_menu = MENU_MAIN; + default: + fprintf(stderr, "Attempt to enter wrong menu!\n"); + to_menu = MENU_MAIN; } if (to_menu != 0) @@ -304,4 +326,3 @@ int menu_handler() { return 1; } - diff --git a/source/patch/base.c b/source/patch/base.c index 461c1a7..847740a 100644 --- a/source/patch/base.c +++ b/source/patch/base.c @@ -2,9 +2,9 @@ // Do you like examples? -PATCH(example) { - fprintf(stderr, "Testing, testing, 1, 2, 3, 4..\n"); +PATCH(example) +{ + fprintf(stderr, "Testing, testing, 1, 2, 3, 4..\n"); - return 0; + return 0; } - diff --git a/source/patch/module.c b/source/patch/module.c index 0855b99..b10b978 100644 --- a/source/patch/module.c +++ b/source/patch/module.c @@ -1,76 +1,92 @@ #include "patch_file.h" -PATCH(modules) { - // TODO - load module cxi here - FILE* f = fopen(PATH_MODULES "/loader.cxi", "r"); - if (!f) { - fprintf(stderr, "Module: loader.cxi not found on FS\n"); - return 2; - } +PATCH(modules) +{ + // TODO - load module cxi here + FILE* f = fopen(PATH_MODULES "/loader.cxi", "r"); + if (!f) { + fprintf(stderr, "Module: loader.cxi not found on FS\n"); + return 2; + } - uint32_t size = fsize(f); - fread((uint8_t*)FCRAM_JUNK_LOCATION, 1, size, f); - fclose(f); + uint32_t size = fsize(f); + fread((uint8_t*)FCRAM_JUNK_LOCATION, 1, size, f); + fclose(f); - // Look for the section that holds all the sysmodules - firm_section_h *sysmodule_section = NULL; - for (firm_section_h *section = firm_loc->section; section < firm_loc->section + 4; section++) { - if (section->address == 0x1FF00000 && section->type == FIRM_TYPE_ARM11) { - sysmodule_section = section; - break; - } - } + // Look for the section that holds all the sysmodules + firm_section_h* sysmodule_section = NULL; + for (firm_section_h* section = firm_loc->section; + section < firm_loc->section + 4; section++) { + if (section->address == 0x1FF00000 && + section->type == FIRM_TYPE_ARM11) { + sysmodule_section = section; + break; + } + } - if (!sysmodule_section) { - fprintf(stderr, "Module: sysmodule section not found\n"); - return 1; - } + if (!sysmodule_section) { + fprintf(stderr, "Module: sysmodule section not found\n"); + return 1; + } - ncch_h *module = (ncch_h*)FCRAM_JUNK_LOCATION; - ncch_h *sysmodule = (ncch_h *)((uint32_t)firm_loc + sysmodule_section->offset); + ncch_h* module = (ncch_h*)FCRAM_JUNK_LOCATION; + ncch_h* sysmodule = + (ncch_h*)((uint32_t)firm_loc + sysmodule_section->offset); - // Check if we want to replace an existing sysmodule - while (sysmodule->magic == NCCH_MAGIC) { - if (memcmp(sysmodule->programID, module->programID, 8) == 0) { - // Expand firmware module size if needed to accomodate replacement. - if (module->contentSize > sysmodule->contentSize) { - uint32_t need_units = (module->contentSize - sysmodule->contentSize); - fprintf(stderr, "Module: Would grow %d units but NYI\n", need_units); - continue; + // Check if we want to replace an existing sysmodule + while (sysmodule->magic == NCCH_MAGIC) { + if (memcmp(sysmodule->programID, module->programID, 8) == 0) { + // Expand firmware module size if needed to accomodate replacement. + if (module->contentSize > sysmodule->contentSize) { + uint32_t need_units = + (module->contentSize - sysmodule->contentSize); + fprintf(stderr, "Module: Would grow %d units but NYI\n", + need_units); + continue; - // TODO - so in a nutshell, the reason Luma works is because it relocates - // the sysmodule section to its final location while fixing the size. - // Once stuff is at the right place, it no longer cares about its' size. + // TODO - so in a nutshell, the reason Luma works is because it + // relocates + // the sysmodule section to its final location while fixing the + // size. + // Once stuff is at the right place, it no longer cares about + // its' size. - // Cakes performs an in-place resize and leaves the copy for later; essentially, - // this means I need to scale EVERYTHING after the increase, and adjust NCCH sections accordingly. + // Cakes performs an in-place resize and leaves the copy for + // later; essentially, + // this means I need to scale EVERYTHING after the increase, and + // adjust NCCH sections accordingly. - // It would be hella easier to just patch at the final location in memory; - // and this was actually mentioned on Luma's issues. - } + // It would be hella easier to just patch at the final location + // in memory; + // and this was actually mentioned on Luma's issues. + } - // Move the remaining modules closer - if (module->contentSize < sysmodule->contentSize) { - fprintf(stderr, "Module: Shrink %d units\n", sysmodule->contentSize - module->contentSize); - int remaining_size = - sysmodule_section->size - + // Move the remaining modules closer + if (module->contentSize < sysmodule->contentSize) { + fprintf(stderr, "Module: Shrink %d units\n", + sysmodule->contentSize - module->contentSize); + int remaining_size = + sysmodule_section->size - (((uint32_t)sysmodule + sysmodule->contentSize * 0x200) - - ((uint32_t)firm_loc + sysmodule_section->offset)); - // Sysmodule section size - (End location of this sysmodule - Sysmodule section) => - memmove((uint8_t*)sysmodule + module->contentSize * 0x200, (uint8_t*)sysmodule + sysmodule->contentSize * 0x200, remaining_size); - // Move end of section to be adjacent - } + ((uint32_t)firm_loc + sysmodule_section->offset)); + // Sysmodule section size - (End location of this sysmodule - + // Sysmodule section) => + memmove((uint8_t*)sysmodule + module->contentSize * 0x200, + (uint8_t*)sysmodule + sysmodule->contentSize * 0x200, + remaining_size); + // Move end of section to be adjacent + } - fprintf(stderr, "Module: Injecting %llu\n", module->programID); - // Copy the module into the firm - memcpy(sysmodule, module, module->contentSize * 0x200); - break; - } - sysmodule = (ncch_h *)((uintptr_t)sysmodule + sysmodule->contentSize * 0x200); - } + fprintf(stderr, "Module: Injecting %llu\n", module->programID); + // Copy the module into the firm + memcpy(sysmodule, module, module->contentSize * 0x200); + break; + } + sysmodule = + (ncch_h*)((uintptr_t)sysmodule + sysmodule->contentSize * 0x200); + } - fprintf(stderr, "Module: injected modules.\n"); + fprintf(stderr, "Module: injected modules.\n"); - return 0; + return 0; } - diff --git a/source/patch/patch_file.h b/source/patch/patch_file.h index 0584d9f..c6c88a6 100644 --- a/source/patch/patch_file.h +++ b/source/patch/patch_file.h @@ -7,25 +7,25 @@ #define BUILTIN 1 #ifdef BUILTIN - // Build patch into CFW instead of as module. - #include "../std/unused.h" - #include "../std/memory.h" - #include "../firm/firm.h" - #include "../firm/fcram.h" - #include "../config.h" - #include "../common.h" - - #define PATCH(name) int patch_##name () +// Build patch into CFW instead of as module. +#include "../std/unused.h" +#include "../std/memory.h" +#include "../firm/firm.h" +#include "../firm/fcram.h" +#include "../config.h" +#include "../common.h" + +#define PATCH(name) int patch_##name() #elif MODULE - // Build patch as loadable executable. +// Build patch as loadable executable. - // TODO - Includes. +// TODO - Includes. - #define PATCH(name) int main() +#define PATCH(name) int main() #else - #define PATCH(name) (void) +#define PATCH(name) (void) - // Don't build patch; Exclude its code. +// Don't build patch; Exclude its code. #endif #endif diff --git a/source/patch/prot.c b/source/patch/prot.c index 2c6181c..376bc42 100644 --- a/source/patch/prot.c +++ b/source/patch/prot.c @@ -2,36 +2,37 @@ // This patch applies the FIRM protection code needed for safe a9lh usage. -PATCH(firmprot) { - uint8_t *firm_mem = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset; - uint32_t size = firm_p9_exefs->fileHeaders[0].size; +PATCH(firmprot) +{ + uint8_t* firm_mem = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + + firm_p9_exefs->fileHeaders[0].offset; + uint32_t size = firm_p9_exefs->fileHeaders[0].size; // We look for 'exe:' first; this string is close to what we patch uint8_t* off = memfind(firm_mem, size, (uint8_t*)"exe:", 4); - if(off == NULL) { - fprintf(stderr, "Couldn't find 'exe:' string.\n"); - return 1; - } + if (off == NULL) { + fprintf(stderr, "Couldn't find 'exe:' string.\n"); + return 1; + } - fprintf(stderr, "Firmprot: 'exe:' string @ %x\n", (uint32_t)off); + fprintf(stderr, "Firmprot: 'exe:' string @ %x\n", (uint32_t)off); - uint8_t pattern[] = {0x00, 0x28, 0x01, 0xDA}; + uint8_t pattern[] = { 0x00, 0x28, 0x01, 0xDA }; uint8_t* firmprot = memfind(off - 0x100, 0x100, pattern, 4); - if(firmprot == NULL) { - fprintf(stderr, "Couldn't find firmprot code.\n"); - return 2; - } + if (firmprot == NULL) { + fprintf(stderr, "Couldn't find firmprot code.\n"); + return 2; + } - fprintf(stderr, "Firmprot: %x\n", (uint32_t)firmprot); + fprintf(stderr, "Firmprot: %x\n", (uint32_t)firmprot); - uint8_t patch[] = {0x00, 0x20, 0xC0, 0x46}; - memcpy(firmprot, patch, 4); + uint8_t patch[] = { 0x00, 0x20, 0xC0, 0x46 }; + memcpy(firmprot, patch, 4); - fprintf(stderr, "Applied firmprot patch.\n"); + fprintf(stderr, "Applied firmprot patch.\n"); - return 0; + return 0; } - diff --git a/source/patch/sig.c b/source/patch/sig.c index 139f406..376d906 100644 --- a/source/patch/sig.c +++ b/source/patch/sig.c @@ -2,43 +2,44 @@ // This patch is responsible for fixing signature checks for the firmware. -PATCH(signatures) { - //Look for signature checks +PATCH(signatures) +{ + // Look for signature checks - uint8_t pat1[] = {0xC0, 0x1C, 0x76, 0xE7}; - uint8_t pat2[] = {0xB5, 0x22, 0x4D, 0x0C}; + uint8_t pat1[] = { 0xC0, 0x1C, 0x76, 0xE7 }; + uint8_t pat2[] = { 0xB5, 0x22, 0x4D, 0x0C }; - // The code segment. - uint8_t *firm_mem = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset; - uint32_t size = firm_p9_exefs->fileHeaders[0].size; + // The code segment. + uint8_t* firm_mem = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + + firm_p9_exefs->fileHeaders[0].offset; + uint32_t size = firm_p9_exefs->fileHeaders[0].size; - uint8_t *off = memfind(firm_mem, size, pat1, 4); + uint8_t* off = memfind(firm_mem, size, pat1, 4); - // We're subbing one because the code goes back 1. - // Unique patterns, etc. - uint8_t *off2 = memfind(firm_mem, size, pat2, 4) - 1; + // We're subbing one because the code goes back 1. + // Unique patterns, etc. + uint8_t* off2 = memfind(firm_mem, size, pat2, 4) - 1; - if (off == NULL) { - fprintf(stderr, "Signature patch failed on P0.\n"); - return 1; // Failed to find sigpatch. Ugh. - } + if (off == NULL) { + fprintf(stderr, "Signature patch failed on P0.\n"); + return 1; // Failed to find sigpatch. Ugh. + } - if (off2 == NULL) { - fprintf(stderr, "Signature patch failed on P1.\n"); - return 2; // Failed to find sigpatch. Ugh. - } + if (off2 == NULL) { + fprintf(stderr, "Signature patch failed on P1.\n"); + return 2; // Failed to find sigpatch. Ugh. + } - fprintf(stderr, "Signatures[0]: 0x%x\n", (uint32_t)off); - fprintf(stderr, "Signatures[1]: 0x%x\n", (uint32_t)off2); + fprintf(stderr, "Signatures[0]: 0x%x\n", (uint32_t)off); + fprintf(stderr, "Signatures[1]: 0x%x\n", (uint32_t)off2); - // See asm/sigpatches.s for the code here - uint8_t sigpatch[] = {0x00, 0x20, 0x70, 0x47}; + // See asm/sigpatches.s for the code here + uint8_t sigpatch[] = { 0x00, 0x20, 0x70, 0x47 }; - memcpy(off, sigpatch, 2); - memcpy(off2, sigpatch, 4); + memcpy(off, sigpatch, 2); + memcpy(off2, sigpatch, 4); - fprintf(stderr, "Signature patch succeded.\n"); + fprintf(stderr, "Signature patch succeded.\n"); - return 0; + return 0; } - diff --git a/source/patch/svc.c b/source/patch/svc.c index 770c819..a77ed88 100644 --- a/source/patch/svc.c +++ b/source/patch/svc.c @@ -1,73 +1,90 @@ #include "patch_file.h" -// This patch handles replacement of services. This includes backdoor, but not just backdoor. -// Any service can be replaced provided there's enough space within the exception page. +// This patch handles replacement of services. This includes backdoor, but not +// just backdoor. +// Any service can be replaced provided there's enough space within the +// exception page. // Please note that the actual code for services is in `external/service`. -uint32_t *getSvcAndExceptions(uint8_t *pos, uint32_t size, uint32_t **exceptionsPage) { - uint8_t pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif +uint32_t* +getSvcAndExceptions(uint8_t* pos, uint32_t size, uint32_t** exceptionsPage) +{ + uint8_t pattern[] = { 0x00, 0xB0, 0x9C, 0xE5 }; // cpsid aif - *exceptionsPage = (uint32_t *)memfind(pos, size, pattern, 4) - 0xB; + *exceptionsPage = (uint32_t*)memfind(pos, size, pattern, 4) - 0xB; - uint32_t svcOffset = (-(((*exceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch - uint32_t *svcTable = (uint32_t *)(pos + *(uint32_t *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address - while(*svcTable) svcTable++; //Look for SVC0 (NULL) + uint32_t svcOffset = + (-(((*exceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - + 8; // Branch offset + 8 for prefetch + uint32_t* svcTable = (uint32_t*)(pos + + *(uint32_t*)(pos + 0xFFFF0008 - svcOffset - + 0xFFF00000 + 8) - + 0xFFF00000); // SVC handler address + while (*svcTable) + svcTable++; // Look for SVC0 (NULL) return svcTable; } -uint32_t *freeSpace = NULL; +uint32_t* freeSpace = NULL; -PATCH(services) { +PATCH(services) +{ // Make sure svcBackdoor is there. uint8_t* arm11Section1 = (uint8_t*)firm_loc + firm_loc->section[1].offset; - uint32_t *exceptionsPage; - uint32_t *svcTable = getSvcAndExceptions(arm11Section1, firm_loc->section[1].size, &exceptionsPage); + uint32_t* exceptionsPage; + uint32_t* svcTable = getSvcAndExceptions( + arm11Section1, firm_loc->section[1].size, &exceptionsPage); - fprintf(stderr, "Svc: table at %x\n", (uint32_t)svcTable); + fprintf(stderr, "Svc: table at %x\n", (uint32_t)svcTable); - char str[] = PATH_SERVICES "/00.bin"; - char* at = str + (strlen(str) - 6); - for(uint32_t i=0; i <= 0xff; i++) { - // Get string for svc. - at[0] = ("0123456789abcdef")[((i >> 4) & 0xf)]; // This is just hexdump. Nothing complicated. - at[1] = ("0123456789abcdef")[(i & 0xf)]; + char str[] = PATH_SERVICES "/00.bin"; + char* at = str + (strlen(str) - 6); + for (uint32_t i = 0; i <= 0xff; i++) { + // Get string for svc. + at[0] = ("0123456789abcdef")[( + (i >> 4) & 0xf)]; // This is just hexdump. Nothing complicated. + at[1] = ("0123456789abcdef")[(i & 0xf)]; - FILE* data = fopen(str, "r"); - if (!data) { - continue; // No file for svc. Move on. - } + FILE* data = fopen(str, "r"); + if (!data) { + continue; // No file for svc. Move on. + } - // Refuse to replace non-NULL services unless the user says to. - if (svcTable[i] && !config.options[OPTION_REPLACE_ALLOCATED_SVC]) { - fclose(data); - fprintf(stderr, "Svc: %x non-null, moving on\n", i); - continue; - } + // Refuse to replace non-NULL services unless the user says to. + if (svcTable[i] && !config.options[OPTION_REPLACE_ALLOCATED_SVC]) { + fclose(data); + fprintf(stderr, "Svc: %x non-null, moving on\n", i); + continue; + } - uint32_t size = fsize(data); - uint8_t* read_to = (void*)FCRAM_JUNK_LOCATION; + uint32_t size = fsize(data); + uint8_t* read_to = (void*)FCRAM_JUNK_LOCATION; - fprintf(stderr, "Svc: %s, %d bytes\n", at, size); + fprintf(stderr, "Svc: %s, %d bytes\n", at, size); - fread(read_to, 1, size, data); + fread(read_to, 1, size, data); - fclose(data); + fclose(data); - if (!freeSpace) { - for(freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; freeSpace++); - } + if (!freeSpace) { + for (freeSpace = exceptionsPage; *freeSpace != 0xFFFFFFFF; + freeSpace++) + ; + } - fprintf(stderr, "Svc: Copy code to %x\n", (uint32_t)freeSpace); + fprintf(stderr, "Svc: Copy code to %x\n", (uint32_t)freeSpace); memcpy(freeSpace, read_to, size); - svcTable[i] = 0xFFFF0000 + ((uint8_t *)freeSpace - (uint8_t *)exceptionsPage); + svcTable[i] = + 0xFFFF0000 + ((uint8_t*)freeSpace - (uint8_t*)exceptionsPage); - freeSpace += size; // We keep track of this because there's more than 7B free. + freeSpace += + size; // We keep track of this because there's more than 7B free. - fprintf(stderr, "Svc: entry set as %x\n", svcTable[0x7B]); - } + fprintf(stderr, "Svc: entry set as %x\n", svcTable[0x7B]); + } - return 0; + return 0; } diff --git a/source/patch_format.h b/source/patch_format.h index 2f624dd..580cc27 100644 --- a/source/patch_format.h +++ b/source/patch_format.h @@ -1,90 +1,108 @@ #ifndef __PATCH_FORMAT_H #define __PATCH_FORMAT_H -// The following are titleids which are handled specially for one reason or another. -// We use titleIDs to be generic; it ensures that patches can share the same format +// The following are titleids which are handled specially for one reason or +// another. +// We use titleIDs to be generic; it ensures that patches can share the same +// format // regardless of whether they're intended for loader or not. Simple logistics. -#define NATIVE_FIRM_TITLEID 0x0004013800000002llu // NATIVE_FIRM +#define NATIVE_FIRM_TITLEID 0x0004013800000002llu // NATIVE_FIRM #define NATIVE_FIRM_N3DS_TITLEID 0x0004013820000002llu // NATIVE_FIRM, n3ds -#define TWL_FIRM_TITLEID 0x0004013000000102llu // TWL_FIRM (DSi Firmware) -#define TWL_FIRM_N3DS_TITLEID 0x0004013020000102llu // TWL_FIRM, n3ds (DSi Firmware) +#define TWL_FIRM_TITLEID 0x0004013000000102llu // TWL_FIRM (DSi Firmware) +#define TWL_FIRM_N3DS_TITLEID \ + 0x0004013020000102llu // TWL_FIRM, n3ds (DSi Firmware) -#define AGB_FIRM_TITLEID 0x0004013000000202llu // AGB_FIRM (GBA firmware) -#define AGB_FIRM_N3DS_TITLEID 0x0004013020000202llu // AGB_FIRM (GBA firmware) +#define AGB_FIRM_TITLEID 0x0004013000000202llu // AGB_FIRM (GBA firmware) +#define AGB_FIRM_N3DS_TITLEID 0x0004013020000202llu // AGB_FIRM (GBA firmware) -#define LOADER_TITLEID 0x0004013000001302llu // Loader is handled specially. +#define LOADER_TITLEID 0x0004013000001302llu // Loader is handled specially. -#define PATCH_MANDATORY (1 << 0) // Patch must be applied for successful boot. -#define PATCH_FAIL_ABORT (1 << 1) // If patch fails to apply, abort and show an error. -#define PATCH_DISABLED (1 << 2) // Do not allow changing this patch's status. With PATCH_MANDATORY, this prevents disabling it. +#define PATCH_MANDATORY (1 << 0) // Patch must be applied for successful boot. +#define PATCH_FAIL_ABORT \ + (1 << 1) // If patch fails to apply, abort and show an error. +#define PATCH_DISABLED \ + (1 << 2) // Do not allow changing this patch's status. With PATCH_MANDATORY, + // this prevents disabling it. // You can redefine this in the Makefile, if you'd like. // Recommended names for being silly: // Windows // system #ifndef PATH_CFW - #define PATH_CFW "/corbenik" // CFW root directory. +#define PATH_CFW "/corbenik" // CFW root directory. #endif -#define PATH_CONFIG_DIR PATH_CFW "/etc" // Config file directory. -#define PATH_CONFIG PATH_CONFIG_DIR "/main.conf" // Config file. -#define PATH_LOCEMU PATH_CONFIG_DIR "/langemu.conf" // Locale emulation config -#define PATH_CPU_CFG PATH_CONFIG_DIR "/cpu.conf" // CPU settings config +#define PATH_CONFIG_DIR PATH_CFW "/etc" // Config file directory. +#define PATH_CONFIG PATH_CONFIG_DIR "/main.conf" // Config file. +#define PATH_LOCEMU PATH_CONFIG_DIR "/langemu.conf" // Locale emulation config +#define PATH_CPU_CFG PATH_CONFIG_DIR "/cpu.conf" // CPU settings config -#define PATH_PATCHES PATH_CFW "/bin" // Patch binary folder. -#define PATH_FIRMWARES PATH_CFW "/lib/firmware" // Firmware folder. -#define PATH_MODULES PATH_CFW "/lib/module" // Sysmodule location -#define PATH_SERVICES PATH_CFW "/lib/service" // Service code location. -#define PATH_TEMP PATH_CFW "/tmp" // Files that are transient (user can delete them and they will be regenerated) -#define PATH_KEYS PATH_CFW "/share/keys" // Keyfiles will be loaded from this dir, and additionally the root if not found. -#define PATH_EXEFS PATH_CFW "/lib/exe" // ExeFS overrides, named like '.exefs' +#define PATH_PATCHES PATH_CFW "/bin" // Patch binary folder. +#define PATH_FIRMWARES PATH_CFW "/lib/firmware" // Firmware folder. +#define PATH_MODULES PATH_CFW "/lib/module" // Sysmodule location +#define PATH_SERVICES PATH_CFW "/lib/service" // Service code location. +#define PATH_TEMP \ + PATH_CFW "/tmp" // Files that are transient (user can delete them and they + // will be regenerated) +#define PATH_KEYS \ + PATH_CFW "/share/keys" // Keyfiles will be loaded from this dir, and + // additionally the root if not found. +#define PATH_EXEFS \ + PATH_CFW "/lib/exe" // ExeFS overrides, named like '.exefs' -#define PATH_NATIVE_F PATH_FIRMWARES "/native" -#define PATH_AGB_F PATH_FIRMWARES "/agb" -#define PATH_TWL_F PATH_FIRMWARES "/twl" +#define PATH_NATIVE_F PATH_FIRMWARES "/native" +#define PATH_AGB_F PATH_FIRMWARES "/agb" +#define PATH_TWL_F PATH_FIRMWARES "/twl" -#define PATH_NATIVE_CETK PATH_FIRMWARES "/native.cetk" +#define PATH_NATIVE_CETK PATH_FIRMWARES "/native.cetk" -#define PATH_TWL_CETK PATH_FIRMWARES "/twl.cetk" +#define PATH_TWL_CETK PATH_FIRMWARES "/twl.cetk" -#define PATH_AGB_CETK PATH_FIRMWARES "/agb.cetk" +#define PATH_AGB_CETK PATH_FIRMWARES "/agb.cetk" -#define PATH_NATIVE_FIRMKEY PATH_KEYS "/native.key" -#define PATH_TWL_FIRMKEY PATH_KEYS "/twl.key" -#define PATH_AGB_FIRMKEY PATH_KEYS "/agb.key" +#define PATH_NATIVE_FIRMKEY PATH_KEYS "/native.key" +#define PATH_TWL_FIRMKEY PATH_KEYS "/twl.key" +#define PATH_AGB_FIRMKEY PATH_KEYS "/agb.key" // These are used with O3DS units. Keep in mind I have no way to test this. -#define PATH_NATIVE_FIRMKEY_2 PATH_KEYS "/native_old.key" -#define PATH_TWL_FIRMKEY_2 PATH_KEYS "/twl_old.key" -#define PATH_AGB_FIRMKEY_2 PATH_KEYS "/agb_old.key" +#define PATH_NATIVE_FIRMKEY_2 PATH_KEYS "/native_old.key" +#define PATH_TWL_FIRMKEY_2 PATH_KEYS "/twl_old.key" +#define PATH_AGB_FIRMKEY_2 PATH_KEYS "/agb_old.key" -#define PATH_SLOT0X11KEY96 PATH_KEYS "/11.key" +#define PATH_SLOT0X11KEY96 PATH_KEYS "/11.key" -#define PATH_ALT_SLOT0X11KEY96 "/slot0x11key96.bin" // Hey, your perrogative, buddy. I like cleaned up paths. +#define PATH_ALT_SLOT0X11KEY96 \ + "/slot0x11key96.bin" // Hey, your perrogative, buddy. I like cleaned up + // paths. // Structure of a patch file. -struct system_patch { - char magic[4]; // "AIDA" for shits and giggles and because we like .hack. - uint32_t patch_ver; // Version of the patch itself. - uint32_t load_ver; // Version of the CFW the patch is intended for. +struct system_patch +{ + char magic[4]; // "AIDA" for shits and giggles and because we like .hack. + uint32_t patch_ver; // Version of the patch itself. + uint32_t load_ver; // Version of the CFW the patch is intended for. - char name[64]; // User-readable name for patch in menu. - char desc[256]; // User-readable description for patch in menu. - uint64_t patch_id; // Unique ID for patch. Each unique patch should provide a unique ID. + char name[64]; // User-readable name for patch in menu. + char desc[256]; // User-readable description for patch in menu. + uint64_t patch_id; // Unique ID for patch. Each unique patch should provide + // a unique ID. - uint64_t tid; // What title this patch is intended for. Certain values are specially handled. + uint64_t tid; // What title this patch is intended for. Certain values are + // specially handled. - uint8_t extra_flags; // Extra flags for patch. + uint8_t extra_flags; // Extra flags for patch. - uint64_t depends[16]; // What patches need to be applied for this patch to be applied; as unique IDs + uint64_t depends[16]; // What patches need to be applied for this patch to + // be applied; as unique IDs - uint32_t patch_size; // Size of the following patch data. -// uint8_t patch_data[]; // The data for the patch. This is a compiled binary for ARM9/11. + uint32_t patch_size; // Size of the following patch data. + // uint8_t patch_data[]; // The data for the patch. This is a + // compiled binary for ARM9/11. } __attribute__((packed)); -struct patch_opcode { +struct patch_opcode +{ } __attribute__((packed)); #endif - diff --git a/source/patcher.c b/source/patcher.c index d4e3c23..973e0d4 100644 --- a/source/patcher.c +++ b/source/patcher.c @@ -15,87 +15,73 @@ extern int patch_firmprot(); extern int patch_services(); extern int patch_modules(); -// A portion of this file is inherited from Luma3DS. -/*u32 getLoader(u8 *pos, u32 *loaderSize) { - u8 *off = pos; - u32 size; - - while(1) - { - size = *(u32 *)(off + 0x104) * 0x200; - if(*(u32 *)(off + 0x200) == 0x64616F6C) break; - off += size; - } - - *loaderSize = size; - - return (u32)(off - pos); -} -*/ - extern int doing_autoboot; -void wait() { - if (config.options[OPTION_TRACE] && !doing_autoboot) { - fprintf(stderr, " [WAIT]"); - wait_key(); - } - fprintf(stderr, "\r \r"); +void +wait() +{ + if (config.options[OPTION_TRACE] && !doing_autoboot) { + fprintf(stderr, " [WAIT]"); + wait_key(); + } + fprintf(stderr, "\r \r"); } -int patch_firm_all() { - // FIXME - Linker is bork at the moment. -// execp(PATH_PATCHES "/example.vco"); +int +patch_firm_all() +{ + // FIXME - Linker is bork at the moment. + // execp(PATH_PATCHES "/example.vco"); -// wait(); + // wait(); - // Use builtin signature patcher? + // Use builtin signature patcher? - wait(); + wait(); - if (config.options[OPTION_SIGPATCH]) { - // TODO - Patch menu. This is okay-ish for now. -// if(execp(PATH_PATCHES "/signatures.vco")) { - if(patch_signatures()) { - abort("Fatal. Sigpatch has failed."); - } - } + if (config.options[OPTION_SIGPATCH]) { + // TODO - Patch menu. This is okay-ish for now. + // if(execp(PATH_PATCHES "/signatures.vco")) { + if (patch_signatures()) { + abort("Fatal. Sigpatch has failed."); + } + } - wait(); + wait(); - if (config.options[OPTION_FIRMPROT]) { - if(patch_firmprot()) { - abort("Fatal. Firmprot has failed."); - } - } + if (config.options[OPTION_FIRMPROT]) { + if (patch_firmprot()) { + abort("Fatal. Firmprot has failed."); + } + } - wait(); + wait(); - // Replace loader? - if (config.options[OPTION_LOADER]) { - if(patch_modules()) { - abort("Fatal. Service patch has failed."); - } - // This requires OPTION_SIGPATCH. - } + // Replace loader? + if (config.options[OPTION_LOADER]) { + if (patch_modules()) { + abort("Fatal. Service patch has failed."); + } + // This requires OPTION_SIGPATCH. + } - wait(); + wait(); - // Inject services? - if (config.options[OPTION_SERVICES]) { - if(patch_services()) { - abort("Fatal. Service patch has failed."); - } - } + // Inject services? + if (config.options[OPTION_SERVICES]) { + if (patch_services()) { + abort("Fatal. Service patch has failed."); + } + } - // Use ARM9 hook thread? - if (config.options[OPTION_ARM9THREAD]) { - // Yes. + // Use ARM9 hook thread? + if (config.options[OPTION_ARM9THREAD]) { + // Yes. - // FIXME - NYI - } + // FIXME - NYI + } - wait(); + wait(); - return 0; + return 0; } diff --git a/source/std/abort.h b/source/std/abort.h index 39ac0f4..8140563 100644 --- a/source/std/abort.h +++ b/source/std/abort.h @@ -3,10 +3,12 @@ #include "draw.h" -#define abort(x...) { \ - fprintf(stderr, x); \ - fumount(); \ - while(1); \ -} +#define abort(x...) \ + { \ + fprintf(stderr, x); \ + fumount(); \ + while (1) \ + ; \ + } #endif diff --git a/source/std/draw.c b/source/std/draw.c index a59f2a3..0695573 100644 --- a/source/std/draw.c +++ b/source/std/draw.c @@ -12,101 +12,112 @@ static unsigned int top_cursor_x = 0, top_cursor_y = 0; static unsigned int bottom_cursor_x = 0, bottom_cursor_y = 0; -static char text_buffer_top [TEXT_TOP_HEIGHT*TEXT_TOP_WIDTH+1]; -static char text_buffer_bottom [TEXT_BOTTOM_HEIGHT*TEXT_BOTTOM_WIDTH+1]; +static char text_buffer_top[TEXT_TOP_HEIGHT * TEXT_TOP_WIDTH + 1]; +static char text_buffer_bottom[TEXT_BOTTOM_HEIGHT * TEXT_BOTTOM_WIDTH + 1]; -static char color_buffer_top [TEXT_TOP_HEIGHT*TEXT_TOP_WIDTH+1]; -static char color_buffer_bottom [TEXT_BOTTOM_HEIGHT*TEXT_BOTTOM_WIDTH+1]; +static char color_buffer_top[TEXT_TOP_HEIGHT * TEXT_TOP_WIDTH + 1]; +static char color_buffer_bottom[TEXT_BOTTOM_HEIGHT * TEXT_BOTTOM_WIDTH + 1]; static uint32_t colors[16] = { - 0x000000, // Black - 0xaa0000, // Blue - 0x00aa00, // Green - 0xaaaa00, // Cyan - 0x0000aa, // Red - 0xaa00aa, // Magenta - 0x0055aa, // Brown - 0xaaaaaa, // Gray - 0x555555, // Dark gray - 0xff5555, // Bright blue - 0x55ff55, // Bright green - 0xffff55, // Bright cyan - 0x5555ff, // Bright red - 0xff55ff, // Bright megenta - 0x55ffff, // Yellow - 0xffffff // White + 0x000000, // Black + 0xaa0000, // Blue + 0x00aa00, // Green + 0xaaaa00, // Cyan + 0x0000aa, // Red + 0xaa00aa, // Magenta + 0x0055aa, // Brown + 0xaaaaaa, // Gray + 0x555555, // Dark gray + 0xff5555, // Bright blue + 0x55ff55, // Bright green + 0xffff55, // Bright cyan + 0x5555ff, // Bright red + 0xff55ff, // Bright megenta + 0x55ffff, // Yellow + 0xffffff // White }; -void clear_disp(uint8_t* screen) { +void +clear_disp(uint8_t* screen) +{ if (screen == TOP_SCREEN) screen = framebuffers->top_left; else if (screen == BOTTOM_SCREEN) screen = framebuffers->bottom; - if(screen == framebuffers->top_left || - screen == framebuffers->top_right) { - memset(screen, 0, SCREEN_TOP_SIZE); - } else if(screen == framebuffers->bottom) { - memset(screen, 0, SCREEN_BOTTOM_SIZE); - } + if (screen == framebuffers->top_left || screen == framebuffers->top_right) { + memset(screen, 0, SCREEN_TOP_SIZE); + } else if (screen == framebuffers->bottom) { + memset(screen, 0, SCREEN_BOTTOM_SIZE); + } } -void clear_text(uint8_t* screen) { +void +clear_text(uint8_t* screen) +{ if (screen == TOP_SCREEN) screen = framebuffers->top_left; else if (screen == BOTTOM_SCREEN) screen = framebuffers->bottom; - if(screen == framebuffers->top_left || - screen == framebuffers->top_right) { - for(int i=0; i < TEXT_TOP_HEIGHT; i++) { - text_buffer_top[i*TEXT_TOP_WIDTH] = 0; - color_buffer_top[i*TEXT_TOP_WIDTH] = 0; - } - } else if(screen == framebuffers->bottom) { - for(int i=0; i < TEXT_BOTTOM_HEIGHT; i++) { - text_buffer_bottom[i*TEXT_BOTTOM_WIDTH] = 0; - color_buffer_bottom[i*TEXT_BOTTOM_WIDTH] = 0; - } - } + if (screen == framebuffers->top_left || screen == framebuffers->top_right) { + for (int i = 0; i < TEXT_TOP_HEIGHT; i++) { + text_buffer_top[i * TEXT_TOP_WIDTH] = 0; + color_buffer_top[i * TEXT_TOP_WIDTH] = 0; + } + } else if (screen == framebuffers->bottom) { + for (int i = 0; i < TEXT_BOTTOM_HEIGHT; i++) { + text_buffer_bottom[i * TEXT_BOTTOM_WIDTH] = 0; + color_buffer_bottom[i * TEXT_BOTTOM_WIDTH] = 0; + } + } } -void clear_screen(uint8_t* screen) { - clear_disp(screen); - clear_text(screen); +void +clear_screen(uint8_t* screen) +{ + clear_disp(screen); + clear_text(screen); } -void set_cursor(void* channel, unsigned int x, unsigned int y) { - if (channel == TOP_SCREEN) { +void +set_cursor(void* channel, unsigned int x, unsigned int y) +{ + if (channel == TOP_SCREEN) { top_cursor_x = x; top_cursor_y = y; - } else if (channel == BOTTOM_SCREEN) { + } else if (channel == BOTTOM_SCREEN) { bottom_cursor_x = x; bottom_cursor_y = y; - } + } } -void clear_screens() { +void +clear_screens() +{ clear_screen(framebuffers->top_left); clear_screen(framebuffers->bottom); } -void draw_character(uint8_t* screen, const char character, const unsigned int buf_x, const unsigned int buf_y, const uint32_t color_fg, const uint32_t color_bg) { +void +draw_character(uint8_t* screen, const char character, const unsigned int buf_x, + const unsigned int buf_y, const uint32_t color_fg, + const uint32_t color_bg) +{ if (!isprint(character)) return; // Don't output non-printables. - _UNUSED int width = 0; - int height = 0; - if(screen == framebuffers->top_left || - screen == framebuffers->top_right) { - width = SCREEN_TOP_WIDTH; - height = SCREEN_TOP_HEIGHT; - } else if(screen == framebuffers->bottom) { - width = SCREEN_BOTTOM_WIDTH; - height = SCREEN_BOTTOM_HEIGHT; - } else { - return; // Invalid buffer. - } + _UNUSED int width = 0; + int height = 0; + if (screen == framebuffers->top_left || screen == framebuffers->top_right) { + width = SCREEN_TOP_WIDTH; + height = SCREEN_TOP_HEIGHT; + } else if (screen == framebuffers->bottom) { + width = SCREEN_BOTTOM_WIDTH; + height = SCREEN_BOTTOM_HEIGHT; + } else { + return; // Invalid buffer. + } unsigned int pos_x = buf_x * 8; unsigned int pos_y = buf_y * 8; @@ -115,9 +126,11 @@ void draw_character(uint8_t* screen, const char character, const unsigned int bu unsigned char char_pos = font[character * 8 + y]; for (int x = 7; x >= 0; x--) { - int screen_pos = (pos_x * height * 3 + (height - y - pos_y - 1) * 3) + (7 - x) * 3 * height; + int screen_pos = + (pos_x * height * 3 + (height - y - pos_y - 1) * 3) + + (7 - x) * 3 * height; - screen[screen_pos] = color_bg >> 16; + screen[screen_pos] = color_bg >> 16; screen[screen_pos + 1] = color_bg >> 8; screen[screen_pos + 2] = color_bg; @@ -134,101 +147,111 @@ unsigned char color_top = 0xf0; unsigned char color_bottom = 0xf0; int kill_output = 0; -void shut_up() { - kill_output = !kill_output; +void +shut_up() +{ + kill_output = !kill_output; } -void putc(void* buf, const int c) { +void +putc(void* buf, const int c) +{ if (buf == stdout || buf == stderr) { - if (kill_output) - return; - - unsigned int width = 0; - _UNUSED unsigned int height = 0; - unsigned int *cursor_x = NULL; - unsigned int *cursor_y = NULL; - char *colorbuf = NULL; - char *strbuf = NULL; - - unsigned char* color = NULL; - - if (buf == TOP_SCREEN) { - width = TEXT_TOP_WIDTH; - height = TEXT_TOP_HEIGHT; - colorbuf = color_buffer_top; - strbuf = text_buffer_top; - cursor_x = &top_cursor_x; - cursor_y = &top_cursor_y; - color = &color_top; - } else if (buf == BOTTOM_SCREEN) { - width = TEXT_BOTTOM_WIDTH; - height = TEXT_BOTTOM_HEIGHT; - colorbuf = color_buffer_bottom; - strbuf = text_buffer_bottom; - cursor_x = &bottom_cursor_x; - cursor_y = &bottom_cursor_y; - color = &color_bottom; - } - - if (cursor_x[0] >= width) { - cursor_x[0] = 0; - cursor_y[0]++; - } - - while (cursor_y[0] >= height) { - // Scroll. - for(unsigned int y=0; y < height-1; y++) { - memset(&strbuf[y*width], 0, width); - memset(&colorbuf[y*width], 0, width); - strncpy(&strbuf[y*width], &strbuf[(y+1)*width], width); - strncpy(&colorbuf[y*width], &colorbuf[(y+1)*width], width); - } - memset(&strbuf[(height-1)*width], 0, width); - memset(&colorbuf[(height-1)*width], 0, width); - - cursor_y[0]--; - - clear_disp(buf); // Clear screen. - } - - switch(c) { - case '\n': - strbuf[cursor_y[0]*width+cursor_x[0]] = 0; - colorbuf[cursor_y[0]*width+cursor_x[0]] = 0; - cursor_y[0]++; - // Fall through intentional. - case '\r': - cursor_x[0] = 0; // Reset to beginning of line. - break; - default: - strbuf[cursor_y[0]*width+cursor_x[0]] = c; - colorbuf[cursor_y[0]*width+cursor_x[0]] = *color; - - if (cursor_x[0] + 1 < width) { - strbuf[cursor_y[0]*width+cursor_x[0]+1] = 0; // Terminate. - colorbuf[cursor_y[0]*width+cursor_x[0]+1] = 0; - } - - cursor_x[0]++; - - break; - } - } else { - // FILE*, not stdin or stdout. - fwrite(&c, 1, 1, (FILE*)buf); - } + if (kill_output) + return; + + unsigned int width = 0; + _UNUSED unsigned int height = 0; + unsigned int* cursor_x = NULL; + unsigned int* cursor_y = NULL; + char* colorbuf = NULL; + char* strbuf = NULL; + + unsigned char* color = NULL; + + if (buf == TOP_SCREEN) { + width = TEXT_TOP_WIDTH; + height = TEXT_TOP_HEIGHT; + colorbuf = color_buffer_top; + strbuf = text_buffer_top; + cursor_x = &top_cursor_x; + cursor_y = &top_cursor_y; + color = &color_top; + } else if (buf == BOTTOM_SCREEN) { + width = TEXT_BOTTOM_WIDTH; + height = TEXT_BOTTOM_HEIGHT; + colorbuf = color_buffer_bottom; + strbuf = text_buffer_bottom; + cursor_x = &bottom_cursor_x; + cursor_y = &bottom_cursor_y; + color = &color_bottom; + } + + if (cursor_x[0] >= width) { + cursor_x[0] = 0; + cursor_y[0]++; + } + + while (cursor_y[0] >= height) { + // Scroll. + for (unsigned int y = 0; y < height - 1; y++) { + memset(&strbuf[y * width], 0, width); + memset(&colorbuf[y * width], 0, width); + strncpy(&strbuf[y * width], &strbuf[(y + 1) * width], width); + strncpy(&colorbuf[y * width], &colorbuf[(y + 1) * width], + width); + } + memset(&strbuf[(height - 1) * width], 0, width); + memset(&colorbuf[(height - 1) * width], 0, width); + + cursor_y[0]--; + + clear_disp(buf); // Clear screen. + } + + switch (c) { + case '\n': + strbuf[cursor_y[0] * width + cursor_x[0]] = 0; + colorbuf[cursor_y[0] * width + cursor_x[0]] = 0; + cursor_y[0]++; + // Fall through intentional. + case '\r': + cursor_x[0] = 0; // Reset to beginning of line. + break; + default: + strbuf[cursor_y[0] * width + cursor_x[0]] = c; + colorbuf[cursor_y[0] * width + cursor_x[0]] = *color; + + if (cursor_x[0] + 1 < width) { + strbuf[cursor_y[0] * width + cursor_x[0] + 1] = + 0; // Terminate. + colorbuf[cursor_y[0] * width + cursor_x[0] + 1] = 0; + } + + cursor_x[0]++; + + break; + } + } else { + // FILE*, not stdin or stdout. + fwrite(&c, 1, 1, (FILE*)buf); + } } -void puts(void* buf, const char *string) { - char *ref = (char*)string; +void +puts(void* buf, const char* string) +{ + char* ref = (char*)string; - while(*ref != '\0') { + while (*ref != '\0') { putc(buf, *ref); ref++; } } -void put_int64(void* channel, int64_t n, int length) { +void +put_int64(void* channel, int64_t n, int length) +{ char conv[32], out[32]; memset(conv, 0, 32); memset(out, 0, 32); @@ -242,7 +265,7 @@ void put_int64(void* channel, int64_t n, int length) { conv[i] = n % 10; conv[i] += '0'; ++i; - } while((n /= 10) != 0); + } while ((n /= 10) != 0); if (sign) conv[i++] = '-'; @@ -251,13 +274,15 @@ void put_int64(void* channel, int64_t n, int length) { out[length] = '\0'; int len = strlen(conv); - for(int i=0; i < len; i++) - out[i] = conv[(len-1) - i]; + for (int i = 0; i < len; i++) + out[i] = conv[(len - 1) - i]; puts(channel, out); } -void put_uint64(void* channel, uint64_t n, int length) { +void +put_uint64(void* channel, uint64_t n, int length) +{ char conv[32], out[32]; memset(conv, 0, 32); memset(out, 0, 32); @@ -265,83 +290,101 @@ void put_uint64(void* channel, uint64_t n, int length) { int i = 0; do { conv[i++] = (n % 10) + '0'; - } while((n /= 10) != 0); + } while ((n /= 10) != 0); if (length > 0) out[length] = '\0'; int len = strlen(conv); - for(int i=0; i < len; i++) - out[i] = conv[(len-1) - i]; + for (int i = 0; i < len; i++) + out[i] = conv[(len - 1) - i]; puts(channel, out); } -void put_hexdump(void* channel, unsigned int num) { - uint8_t* num_8 = (uint8_t*)# - for(int i=3; i>=0; i--) { - uint8_t high = (num_8[i] >> 4) & 0xf; - uint8_t low = num_8[i] & 0xf; +void +put_hexdump(void* channel, unsigned int num) +{ + uint8_t* num_8 = (uint8_t*)# + for (int i = 3; i >= 0; i--) { + uint8_t high = (num_8[i] >> 4) & 0xf; + uint8_t low = num_8[i] & 0xf; - putc(channel, ("0123456789abcdef")[high]); - putc(channel, ("0123456789abcdef")[low]); - } + putc(channel, ("0123456789abcdef")[high]); + putc(channel, ("0123456789abcdef")[low]); + } } -void put_uint(void* channel, unsigned int n, int length) { +void +put_uint(void* channel, unsigned int n, int length) +{ put_uint64(channel, n, length); } -void put_int(void* channel, int n, int length) { +void +put_int(void* channel, int n, int length) +{ put_int64(channel, n, length); } -void fflush(void* channel) { +void +fflush(void* channel) +{ if (channel == TOP_SCREEN) { - for(int y=0; y < TEXT_TOP_HEIGHT; y++) { - for(int x=0; x < TEXT_TOP_WIDTH; x++) { - char c = text_buffer_top[y*TEXT_TOP_WIDTH+x]; - if (c == 0) - break; - uint32_t color_fg = colors[((color_buffer_top[y*TEXT_TOP_WIDTH+x] >> 4) & 0x0f)]; - uint32_t color_bg = colors[(color_buffer_top[y*TEXT_TOP_WIDTH+x] & 0x0f)]; - draw_character(framebuffers->top_left, c, x, y, color_fg, color_bg); - } - } + for (int y = 0; y < TEXT_TOP_HEIGHT; y++) { + for (int x = 0; x < TEXT_TOP_WIDTH; x++) { + char c = text_buffer_top[y * TEXT_TOP_WIDTH + x]; + if (c == 0) + break; + uint32_t color_fg = colors[( + (color_buffer_top[y * TEXT_TOP_WIDTH + x] >> 4) & 0x0f)]; + uint32_t color_bg = + colors[(color_buffer_top[y * TEXT_TOP_WIDTH + x] & 0x0f)]; + draw_character(framebuffers->top_left, c, x, y, color_fg, + color_bg); + } + } } else if (channel == BOTTOM_SCREEN) { - for(int y=0; y < TEXT_BOTTOM_HEIGHT; y++) { - for(int x=0; x < TEXT_BOTTOM_WIDTH; x++) { - char c = text_buffer_bottom[y*TEXT_BOTTOM_WIDTH+x]; - if (c == 0) - break; - uint32_t color_fg = colors[((color_buffer_bottom[y*TEXT_BOTTOM_WIDTH+x] >> 4) & 0x0f)]; - uint32_t color_bg = colors[(color_buffer_bottom[y*TEXT_BOTTOM_WIDTH+x] & 0x0f)]; - draw_character(framebuffers->bottom, c, x, y, color_fg, color_bg); - } - } - } else { - f_sync(&(((FILE*)channel)->handle)); // Sync to disk. - } + for (int y = 0; y < TEXT_BOTTOM_HEIGHT; y++) { + for (int x = 0; x < TEXT_BOTTOM_WIDTH; x++) { + char c = text_buffer_bottom[y * TEXT_BOTTOM_WIDTH + x]; + if (c == 0) + break; + uint32_t color_fg = colors[( + (color_buffer_bottom[y * TEXT_BOTTOM_WIDTH + x] >> 4) & + 0x0f)]; + uint32_t color_bg = colors[( + color_buffer_bottom[y * TEXT_BOTTOM_WIDTH + x] & 0x0f)]; + draw_character(framebuffers->bottom, c, x, y, color_fg, + color_bg); + } + } + } else { + f_sync(&(((FILE*)channel)->handle)); // Sync to disk. + } } -void vfprintf(void* channel, const char* format, va_list ap ) { - char *ref = (char*)format; - - unsigned char* color; - if (channel == TOP_SCREEN) - color = &color_top; - else if (channel == TOP_SCREEN) - color = &color_bottom; - - while(*ref != '\0') { - if (*ref == 0x1B && *(++ref) == '[' && ( channel == stdout || channel == stderr) ) { -ansi_codes: +void +vfprintf(void* channel, const char* format, va_list ap) +{ + char* ref = (char*)format; + + unsigned char* color; + if (channel == TOP_SCREEN) + color = &color_top; + else if (channel == TOP_SCREEN) + color = &color_bottom; + + while (*ref != '\0') { + if (*ref == 0x1B && *(++ref) == '[' && + (channel == stdout || channel == stderr)) { + ansi_codes: // Ansi escape code. ++ref; // [30-37] Set text color if (*ref == '3') { ++ref; - if(*ref >= '0' && *ref <= '7') { + if (*ref >= '0' && *ref <= '7') { // Valid FG color. *color &= 0x0f; // Remove fg color. *color |= (*ref - '0') << 4; @@ -350,15 +393,15 @@ ansi_codes: // [40-47] Set bg color else if (*ref == '4') { ++ref; - if(*ref >= '0' && *ref <= '7') { + if (*ref >= '0' && *ref <= '7') { // Valid BG color. *color &= 0xf0; // Remove bg color. *color |= *ref - '0'; } } else if (*ref == '0') { - // Reset. - *color = 0xf0; - } + // Reset. + *color = 0xf0; + } ++ref; @@ -366,43 +409,45 @@ ansi_codes: goto ansi_codes; // Another code. } - // Loop until the character is somewhere 0x40 - 0x7E, which terminates an ANSI sequence - while(!(*ref >= 0x40 && *ref <= 0x7E)) ref++; + // Loop until the character is somewhere 0x40 - 0x7E, which + // terminates an ANSI sequence + while (!(*ref >= 0x40 && *ref <= 0x7E)) + ref++; } else if (*ref == '%') { int type_size = 0; int length = -1; -check_format: + check_format: // Format string. ++ref; - switch(*ref) { + switch (*ref) { case 'd': - switch(type_size) { + switch (type_size) { case 2: - put_int64(channel, va_arg( ap, int64_t ), length); + put_int64(channel, va_arg(ap, int64_t), length); break; default: - put_int(channel, va_arg( ap, int ), length); + put_int(channel, va_arg(ap, int), length); break; } break; case 'u': - switch(type_size) { + switch (type_size) { case 2: - put_uint64(channel, va_arg( ap, uint64_t ), length); + put_uint64(channel, va_arg(ap, uint64_t), length); break; default: - put_uint(channel, va_arg( ap, unsigned int ), length); + put_uint(channel, va_arg(ap, unsigned int), length); break; } break; case 's': - puts(channel, va_arg( ap, char* )); + puts(channel, va_arg(ap, char*)); break; case 'c': - putc(channel, va_arg( ap, int )); + putc(channel, va_arg(ap, int)); break; case 'p': - puts(channel, va_arg( ap, char* )); + puts(channel, va_arg(ap, char*)); break; case '%': putc(channel, '%'); @@ -412,9 +457,9 @@ check_format: case 'l': ++type_size; goto check_format; - case 'x': - put_hexdump(channel, va_arg( ap, unsigned int )); - break; + case 'x': + put_hexdump(channel, va_arg(ap, unsigned int)); + break; default: if (*ref >= '0' && *ref <= '9') { length = *ref - '0'; @@ -431,11 +476,13 @@ check_format: fflush(channel); } -void fprintf(void* channel, const char* format, ...) { +void +fprintf(void* channel, const char* format, ...) +{ va_list ap; - va_start( ap, format ); + va_start(ap, format); - vfprintf( channel, format, ap ); + vfprintf(channel, format, ap); - va_end( ap ); + va_end(ap); } diff --git a/source/std/draw.h b/source/std/draw.h index 77023c4..34212aa 100644 --- a/source/std/draw.h +++ b/source/std/draw.h @@ -15,21 +15,23 @@ #define SCREEN_DEPTH 3 #define SCREEN_TOP_SIZE (SCREEN_TOP_WIDTH * SCREEN_TOP_HEIGHT * SCREEN_DEPTH) -#define SCREEN_BOTTOM_SIZE (SCREEN_BOTTOM_WIDTH * SCREEN_BOTTOM_HEIGHT * SCREEN_DEPTH) +#define SCREEN_BOTTOM_SIZE \ + (SCREEN_BOTTOM_WIDTH * SCREEN_BOTTOM_HEIGHT * SCREEN_DEPTH) #define CHARA_HEIGHT 8 -#define CHARA_WIDTH 8 +#define CHARA_WIDTH 8 -#define TEXT_TOP_WIDTH (SCREEN_TOP_WIDTH / CHARA_WIDTH) -#define TEXT_TOP_HEIGHT (SCREEN_TOP_HEIGHT / CHARA_HEIGHT) +#define TEXT_TOP_WIDTH (SCREEN_TOP_WIDTH / CHARA_WIDTH) +#define TEXT_TOP_HEIGHT (SCREEN_TOP_HEIGHT / CHARA_HEIGHT) -#define TEXT_BOTTOM_WIDTH (SCREEN_BOTTOM_WIDTH / CHARA_WIDTH) +#define TEXT_BOTTOM_WIDTH (SCREEN_BOTTOM_WIDTH / CHARA_WIDTH) #define TEXT_BOTTOM_HEIGHT (SCREEN_BOTTOM_HEIGHT / CHARA_HEIGHT) -#define TEXT_TOP_SIZE (TEXT_TOP_WIDTH * TEXT_TOP_HEIGHT) +#define TEXT_TOP_SIZE (TEXT_TOP_WIDTH * TEXT_TOP_HEIGHT) #define TEXT_BOTTOM_SIZE (TEXT_BOTTOM_WIDTH * TEXT_BOTTOM_HEIGHT) -enum screen { +enum screen +{ screen_top_left, screen_top_right, screen_bottom @@ -37,28 +39,31 @@ enum screen { #include "unused.h" -_UNUSED static struct framebuffers { - uint8_t *top_left; - uint8_t *top_right; - uint8_t *bottom; -} *framebuffers = (struct framebuffers *)0x23FFFE00; +_UNUSED static struct framebuffers +{ + uint8_t* top_left; + uint8_t* top_right; + uint8_t* bottom; +}* framebuffers = (struct framebuffers*)0x23FFFE00; // This is marked unused since it occurs in all files. -#define TOP_FB framebuffers->top_left +#define TOP_FB framebuffers->top_left #define BOTTOM_FB framebuffers->bottom void clear_screen(uint8_t* screen); void clear_screens(); -void draw_character(uint8_t* screen, const char character, const unsigned int pos_x, const unsigned int pos_y, const uint32_t color_fg, const uint32_t color_bg); +void draw_character(uint8_t* screen, const char character, + const unsigned int pos_x, const unsigned int pos_y, + const uint32_t color_fg, const uint32_t color_bg); -#define TOP_SCREEN ((void*)0) +#define TOP_SCREEN ((void*)0) #define BOTTOM_SCREEN ((void*)2) #define stdout TOP_SCREEN #define stderr BOTTOM_SCREEN void putc(void* buf, const int c); -void puts(void* buf, const char *string); +void puts(void* buf, const char* string); void fflush(void* channel); void set_cursor(void* channel, unsigned int x, unsigned int y); @@ -74,25 +79,26 @@ void set_cursor(void* channel, unsigned int x, unsigned int y); // %hh - byte (stub) // %[0-9][0-9] // Formats are also supported (but are subject to replacement) -// %p - unsigned char, changes color of text (will be replaced with ANSI codes eventually) +// %p - unsigned char, changes color of text (will be replaced with ANSI codes +// eventually) void fprintf(void* channel, const char* format, ...); -#define BLACK 0 -#define BLUE 1 -#define GREEN 2 -#define CYAN 3 -#define RED 4 -#define MAGENTA 5 -#define BROWN 6 -#define GRAY 7 -#define D_GRAY 8 -#define B_BLUE 9 -#define B_GREEN 10 -#define B_CYAN 11 -#define B_RED 12 +#define BLACK 0 +#define BLUE 1 +#define GREEN 2 +#define CYAN 3 +#define RED 4 +#define MAGENTA 5 +#define BROWN 6 +#define GRAY 7 +#define D_GRAY 8 +#define B_BLUE 9 +#define B_GREEN 10 +#define B_CYAN 11 +#define B_RED 12 #define B_MAGENTA 13 -#define YELLOW 14 -#define WHITE 15 +#define YELLOW 14 +#define WHITE 15 #define COLOR(fg, bg) "\x1b[3" #fg ";4" #bg "m" diff --git a/source/std/font.h b/source/std/font.h index 7922c35..259d65a 100644 --- a/source/std/font.h +++ b/source/std/font.h @@ -2,134 +2,177 @@ #define __STD_FONT_H static const unsigned char font[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, - 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, - 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x3c, 0x3c, 0x18, 0xff, 0xe7, 0x18, 0x3c, 0x00, - 0x10, 0x38, 0x7c, 0xfe, 0xee, 0x10, 0x38, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, - 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, - 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, - 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x08, 0x0c, 0x0a, 0x0a, 0x08, 0x78, 0xf0, 0x00, - 0x18, 0x14, 0x1a, 0x16, 0x72, 0xe2, 0x0e, 0x1c, 0x10, 0x54, 0x38, 0xee, 0x38, 0x54, 0x10, 0x00, - 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, - 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, - 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x00, 0x1c, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x7e, - 0x18, 0x3c, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x5a, 0x3c, 0x18, 0x00, - 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, - 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00, - 0x00, 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, - 0x6c, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, - 0x10, 0x7c, 0xd0, 0x7c, 0x16, 0xfc, 0x10, 0x00, 0x00, 0x66, 0xac, 0xd8, 0x36, 0x6a, 0xcc, 0x00, - 0x38, 0x4c, 0x38, 0x78, 0xce, 0xcc, 0x7a, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, - 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, - 0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0x7c, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7e, 0x00, - 0x7c, 0xc6, 0x06, 0x1c, 0x70, 0xc6, 0xfe, 0x00, 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00, - 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfe, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, - 0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, - 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, - 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, - 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, - 0x7c, 0x82, 0x9e, 0xa6, 0x9e, 0x80, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, - 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, - 0xfc, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, - 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xce, 0xc6, 0x7e, 0x00, - 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, - 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x82, 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, - 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x06, - 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xe6, 0x00, 0x7c, 0xc6, 0xc0, 0x7c, 0x06, 0xc6, 0x7c, 0x00, - 0x7e, 0x5a, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x82, 0x00, - 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, - 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, - 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, - 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, - 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00, - 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, - 0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x78, - 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0x00, 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, - 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xd6, 0xd6, 0x00, - 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x7c, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, - 0x00, 0x00, 0xde, 0x76, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0x7c, 0x00, - 0x10, 0x30, 0xfc, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, - 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, - 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, - 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00, - 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xe0, 0x00, - 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, - 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, - 0x0e, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x7c, 0x82, 0x38, 0x0c, 0x7c, 0xcc, 0x76, 0x00, - 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, - 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0xc0, 0x7c, 0x18, 0x70, - 0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, - 0xe0, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x38, 0x38, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, - 0x0e, 0x10, 0xfe, 0x60, 0x78, 0x60, 0xfe, 0x00, 0x00, 0x00, 0x7c, 0x12, 0x7e, 0xd0, 0x7e, 0x00, - 0x7e, 0xc8, 0xc8, 0xfe, 0xc8, 0xc8, 0xce, 0x00, 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xe0, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0x7c, 0x82, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, - 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x18, 0x7c, 0xd6, 0xd0, 0xd6, 0x7c, 0x18, 0x00, - 0x38, 0x6c, 0x60, 0xf0, 0x60, 0xf2, 0xdc, 0x00, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x00, - 0xf8, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0x06, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, - 0x0e, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0x0e, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x0e, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, - 0x66, 0x98, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x98, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00, - 0x38, 0x0c, 0x3c, 0x34, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, - 0x30, 0x00, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc0, 0xc8, 0xd0, 0xfe, 0x46, 0x8c, 0x1e, 0x00, - 0xc0, 0xc8, 0xd0, 0xec, 0x5c, 0xbe, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00, - 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, - 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, - 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, - 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, - 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, - 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, - 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, - 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, - 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, - 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x74, 0xcc, 0xc8, 0xdc, 0x76, 0x00, 0x78, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xdc, 0x40, - 0xfe, 0x62, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x02, 0x7e, 0xec, 0x6c, 0x6c, 0x48, 0x00, - 0xfe, 0x62, 0x30, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0xd0, 0xc8, 0xc8, 0x70, 0x00, - 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf8, 0x80, 0x00, 0x00, 0x7e, 0xd8, 0x18, 0x18, 0x10, 0x00, - 0x38, 0x10, 0x7c, 0xd6, 0xd6, 0x7c, 0x10, 0x38, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x7c, 0x00, - 0x7c, 0xc6, 0xc6, 0xc6, 0x6c, 0x28, 0xee, 0x00, 0x3c, 0x22, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, - 0x00, 0x00, 0x66, 0x99, 0x99, 0x66, 0x00, 0x00, 0x00, 0x06, 0x7c, 0x9e, 0xf2, 0x7c, 0xc0, 0x00, - 0x00, 0x00, 0x7c, 0xc0, 0xf8, 0xc0, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, - 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, - 0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x00, - 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, - 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, - 0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x00, - 0xd8, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xc0, 0xf0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, + 0xbd, 0x99, 0x81, 0x7e, 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, + 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x10, 0x38, 0x7c, 0xfe, + 0x7c, 0x38, 0x10, 0x00, 0x3c, 0x3c, 0x18, 0xff, 0xe7, 0x18, 0x3c, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0xee, 0x10, 0x38, 0x00, 0x00, 0x00, 0x18, 0x3c, + 0x3c, 0x18, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, + 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0xff, 0xc3, 0x99, 0xbd, + 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, + 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x08, 0x0c, 0x0a, 0x0a, + 0x08, 0x78, 0xf0, 0x00, 0x18, 0x14, 0x1a, 0x16, 0x72, 0xe2, 0x0e, 0x1c, + 0x10, 0x54, 0x38, 0xee, 0x38, 0x54, 0x10, 0x00, 0x80, 0xe0, 0xf8, 0xfe, + 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, + 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x00, 0x66, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x00, + 0x1c, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x7e, + 0x18, 0x3c, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, + 0x5a, 0x3c, 0x18, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, + 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, + 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, 0x6c, 0x24, 0x24, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, + 0x10, 0x7c, 0xd0, 0x7c, 0x16, 0xfc, 0x10, 0x00, 0x00, 0x66, 0xac, 0xd8, + 0x36, 0x6a, 0xcc, 0x00, 0x38, 0x4c, 0x38, 0x78, 0xce, 0xcc, 0x7a, 0x00, + 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x60, + 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, + 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, + 0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0x7c, 0x00, 0x18, 0x38, 0x78, 0x18, + 0x18, 0x18, 0x7e, 0x00, 0x7c, 0xc6, 0x06, 0x1c, 0x70, 0xc6, 0xfe, 0x00, + 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00, 0x1c, 0x3c, 0x6c, 0xcc, + 0xfe, 0x0c, 0x1e, 0x00, 0xfe, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, + 0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, 0xfe, 0xc6, 0x0c, 0x18, + 0x30, 0x30, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, + 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, + 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, 0x7c, 0x82, 0x9e, 0xa6, + 0x9e, 0x80, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, + 0xc0, 0xc6, 0x7c, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, 0xfe, 0x62, 0x68, 0x78, + 0x68, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xce, 0xc6, 0x7e, 0x00, + 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x3c, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x3c, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, + 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0xf0, 0x60, 0x60, 0x60, + 0x62, 0x66, 0xfe, 0x00, 0x82, 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, + 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0x7c, 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x06, 0xfc, 0x66, 0x66, 0x7c, + 0x66, 0x66, 0xe6, 0x00, 0x7c, 0xc6, 0xc0, 0x7c, 0x06, 0xc6, 0x7c, 0x00, + 0x7e, 0x5a, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0x7c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, + 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x82, 0x00, 0xc6, 0x6c, 0x38, 0x38, + 0x38, 0x6c, 0xc6, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, + 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x78, 0x00, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, + 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, 0x10, 0x38, 0x6c, 0xc6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, + 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00, 0x1c, 0x0c, 0x0c, 0x7c, + 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x76, 0xcc, + 0xcc, 0x7c, 0x0c, 0x78, 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, + 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x0c, 0x00, 0x1c, + 0x0c, 0x0c, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, + 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0xcc, 0xfe, + 0xd6, 0xd6, 0xd6, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0xdc, 0x66, + 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x7c, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, + 0x00, 0x00, 0xde, 0x76, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, + 0x7c, 0x06, 0x7c, 0x00, 0x10, 0x30, 0xfc, 0x30, 0x30, 0x34, 0x18, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0xc6, 0xc6, + 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, + 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, + 0xcc, 0x7c, 0x0c, 0xf8, 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, + 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00, 0x18, 0x18, 0x18, 0x00, + 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xe0, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, + 0xc6, 0xc6, 0xfe, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, + 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x7c, 0xc6, + 0xfe, 0xc0, 0x7c, 0x00, 0x7c, 0x82, 0x38, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0x78, 0x0c, + 0x7c, 0xcc, 0x76, 0x00, 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0x7c, 0xc0, 0xc0, 0x7c, 0x18, 0x70, 0x7c, 0x82, 0x7c, 0xc6, + 0xfe, 0xc0, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0xe0, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x66, 0x00, 0x38, 0x18, + 0x18, 0x18, 0x3c, 0x00, 0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0xe0, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, + 0xfe, 0xc6, 0xc6, 0x00, 0x38, 0x38, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, + 0x0e, 0x10, 0xfe, 0x60, 0x78, 0x60, 0xfe, 0x00, 0x00, 0x00, 0x7c, 0x12, + 0x7e, 0xd0, 0x7e, 0x00, 0x7e, 0xc8, 0xc8, 0xfe, 0xc8, 0xc8, 0xce, 0x00, + 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, + 0xc6, 0xc6, 0x7c, 0x00, 0xe0, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0x82, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0xcc, 0xcc, + 0xcc, 0xcc, 0x76, 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xc6, 0x00, 0xc6, 0xc6, + 0xc6, 0xc6, 0x7c, 0x00, 0x18, 0x7c, 0xd6, 0xd0, 0xd6, 0x7c, 0x18, 0x00, + 0x38, 0x6c, 0x60, 0xf0, 0x60, 0xf2, 0xdc, 0x00, 0x66, 0x3c, 0x18, 0x7e, + 0x18, 0x7e, 0x18, 0x00, 0xf8, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0x06, + 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, 0x0e, 0x10, 0x78, 0x0c, + 0x7c, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x0e, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x0e, 0x10, 0xcc, 0xcc, + 0xcc, 0xcc, 0x76, 0x00, 0x66, 0x98, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, + 0x66, 0x98, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00, 0x38, 0x0c, 0x3c, 0x34, + 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, + 0x30, 0x00, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, + 0xc0, 0xc8, 0xd0, 0xfe, 0x46, 0x8c, 0x1e, 0x00, 0xc0, 0xc8, 0xd0, 0xec, + 0x5c, 0xbe, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00, + 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, + 0x6c, 0xd8, 0x00, 0x00, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0xdb, 0x77, 0xdb, 0xee, + 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, + 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x00, 0x00, 0xf8, 0x18, + 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, + 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x18, 0x18, 0xf8, 0x18, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, + 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x3f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xcc, 0xc8, 0xdc, 0x76, 0x00, + 0x78, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xdc, 0x40, 0xfe, 0x62, 0x60, 0x60, + 0x60, 0x60, 0xf0, 0x00, 0x00, 0x02, 0x7e, 0xec, 0x6c, 0x6c, 0x48, 0x00, + 0xfe, 0x62, 0x30, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0xd0, + 0xc8, 0xc8, 0x70, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf8, 0x80, + 0x00, 0x00, 0x7e, 0xd8, 0x18, 0x18, 0x10, 0x00, 0x38, 0x10, 0x7c, 0xd6, + 0xd6, 0x7c, 0x10, 0x38, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0xc6, 0xc6, 0xc6, 0x6c, 0x28, 0xee, 0x00, 0x3c, 0x22, 0x18, 0x7c, + 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x66, 0x99, 0x99, 0x66, 0x00, 0x00, + 0x00, 0x06, 0x7c, 0x9e, 0xf2, 0x7c, 0xc0, 0x00, 0x00, 0x00, 0x7c, 0xc0, + 0xf8, 0xc0, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, + 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, + 0x18, 0x00, 0x7e, 0x00, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x00, + 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x00, 0x0e, 0x1b, 0x1b, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, + 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x00, + 0xd8, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xc0, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/source/std/fs.c b/source/std/fs.c index bb5fe54..1927922 100644 --- a/source/std/fs.c +++ b/source/std/fs.c @@ -8,18 +8,22 @@ static FATFS fs; static FILE files[MAX_FILES_OPEN]; -int fmount(void) { +int +fmount(void) +{ if (f_mount(&fs, "0:", 1)) return 1; - for(int i=0; i < MAX_FILES_OPEN; i++) + for (int i = 0; i < MAX_FILES_OPEN; i++) memset(&files[i], 0, sizeof(FILE)); return 0; } -int fumount(void) { - for(int i=0; i < MAX_FILES_OPEN; i++) +int +fumount(void) +{ + for (int i = 0; i < MAX_FILES_OPEN; i++) if (files[i].is_open) fclose(&files[i]); @@ -29,23 +33,25 @@ int fumount(void) { return 0; } -FILE* fopen(const char *filename, const char *mode) { +FILE* +fopen(const char* filename, const char* mode) +{ if (*mode != 'r' && *mode != 'w' && *mode != 'a') return NULL; // Mode not valid. FILE* fp; int i; - for(i=0; i < MAX_FILES_OPEN; i++) { - if(!files[i].is_open) { - fp = &files[i]; - break; + for (i = 0; i < MAX_FILES_OPEN; i++) { + if (!files[i].is_open) { + fp = &files[i]; + break; } } if (i == MAX_FILES_OPEN) return NULL; // Out of handles. - fp->mode = (*mode == 'r' ? FA_READ : (FA_WRITE | FA_OPEN_ALWAYS)); + fp->mode = (*mode == 'r' ? FA_READ : (FA_WRITE | FA_OPEN_ALWAYS)); if (f_open(&(fp->handle), filename, fp->mode)) return NULL; @@ -55,62 +61,82 @@ FILE* fopen(const char *filename, const char *mode) { return fp; } -void fclose(FILE* fp) { +void +fclose(FILE* fp) +{ f_close(&(fp->handle)); memset(fp, 0, sizeof(FILE)); } -void fseek(FILE* fp, int64_t offset, int whence) { - uint32_t fixed_offset; - switch(whence) { - case SEEK_SET: - fixed_offset = 0; - break; - case SEEK_CUR: - fixed_offset = ftell(fp); - break; - case SEEK_END: - fixed_offset = fsize(fp); - break; - default: - return; - } - - f_lseek(&(fp->handle), fixed_offset+offset); +void +fseek(FILE* fp, int64_t offset, int whence) +{ + uint32_t fixed_offset; + switch (whence) { + case SEEK_SET: + fixed_offset = 0; + break; + case SEEK_CUR: + fixed_offset = ftell(fp); + break; + case SEEK_END: + fixed_offset = fsize(fp); + break; + default: + return; + } + + f_lseek(&(fp->handle), fixed_offset + offset); } -size_t ftell(FILE* fp) { - return f_tell(&(fp->handle)); +size_t +ftell(FILE* fp) +{ + return f_tell(&(fp->handle)); } -int feof(FILE* fp) { +int +feof(FILE* fp) +{ return f_eof(&(fp->handle)); } -size_t fsize(FILE* fp) { +size_t +fsize(FILE* fp) +{ return f_size(&(fp->handle)); } -size_t fwrite(const void *buffer, size_t elementSize, size_t elementCnt, FILE* fp) { +size_t +fwrite(const void* buffer, size_t elementSize, size_t elementCnt, FILE* fp) +{ UINT br; - if(f_write(&(fp->handle), buffer, elementSize*elementCnt, &br)) return 0; - if (br == elementSize*elementCnt) br /= elementSize; else return 0; + if (f_write(&(fp->handle), buffer, elementSize * elementCnt, &br)) + return 0; + if (br == elementSize * elementCnt) + br /= elementSize; + else + return 0; return br; } -size_t fread(void *buffer, size_t elementSize, size_t elementCnt, FILE* fp) { +size_t +fread(void* buffer, size_t elementSize, size_t elementCnt, FILE* fp) +{ UINT br; - if(f_read(&(fp->handle), buffer, elementSize*elementCnt, &br)) + if (f_read(&(fp->handle), buffer, elementSize * elementCnt, &br)) return 0; - if (br == elementSize*elementCnt) + if (br == elementSize * elementCnt) br /= elementSize; else return 0; return br; } -size_t write_file(void* data, char* path, size_t size) { +size_t +write_file(void* data, char* path, size_t size) +{ FILE* temp = fopen(path, "w"); if (!temp) @@ -123,7 +149,9 @@ size_t write_file(void* data, char* path, size_t size) { return wrote; } -size_t read_file(void* data, char* path, size_t size) { +size_t +read_file(void* data, char* path, size_t size) +{ FILE* temp = fopen(path, "r"); if (!temp) diff --git a/source/std/fs.h b/source/std/fs.h index b53fc34..a9bfc6f 100644 --- a/source/std/fs.h +++ b/source/std/fs.h @@ -7,11 +7,12 @@ #define MAX_FILES_OPEN 64 -typedef struct { - FIL handle; - uint32_t mode; - size_t size; - size_t at; +typedef struct +{ + FIL handle; + uint32_t mode; + size_t size; + size_t at; uint8_t is_open; } __attribute__((packed)) FILE; @@ -19,24 +20,24 @@ typedef struct { #define SEEK_CUR 1 #define SEEK_END 2 -int fmount (void); -int fumount (void); +int fmount(void); +int fumount(void); -FILE* fopen (const char *filename, const char *mode); +FILE* fopen(const char* filename, const char* mode); -void fclose (FILE* fp); +void fclose(FILE* fp); -void fseek (FILE* fp, int64_t offset, int whence); +void fseek(FILE* fp, int64_t offset, int whence); -size_t ftell (FILE* fp); +size_t ftell(FILE* fp); -int feof (FILE* fp); +int feof(FILE* fp); -size_t fsize (FILE* fp); - -size_t fwrite (const void *buffer, size_t elementSize, size_t elementCnt, FILE* fp); -size_t fread (void *buffer, size_t elementSize, size_t elementCnt, FILE* fp); +size_t fsize(FILE* fp); +size_t fwrite(const void* buffer, size_t elementSize, size_t elementCnt, + FILE* fp); +size_t fread(void* buffer, size_t elementSize, size_t elementCnt, FILE* fp); size_t write_file(void* data, char* path, size_t size); size_t read_file(void* data, char* path, size_t size); diff --git a/source/std/memory.c b/source/std/memory.c index e71a4a9..27c7cdb 100644 --- a/source/std/memory.c +++ b/source/std/memory.c @@ -3,23 +3,28 @@ #include #include -int strlen(const char *string) +int +strlen(const char* string) { - char *string_end = (char *)string; - while (*string_end) string_end++; + char* string_end = (char*)string; + while (*string_end) + string_end++; return string_end - string; } -int isprint(char c) { - if (c >= 32 && c <= 127) +int +isprint(char c) +{ + if (c >= 32 && c <= 127) return 1; return 0; } -void memcpy(void *dest, const void *src, size_t size) +void +memcpy(void* dest, const void* src, size_t size) { - char *destc = (char *)dest; - const char *srcc = (const char *)src; + char* destc = (char*)dest; + const char* srcc = (const char*)src; // If we can align both dest and src together... if ((uintptr_t)srcc % sizeof(size_t) == (uintptr_t)destc % sizeof(size_t)) { @@ -29,8 +34,9 @@ void memcpy(void *dest, const void *src, size_t size) } for (; size >= sizeof(size_t); size -= sizeof(size_t), - destc += sizeof(size_t), srcc += sizeof(size_t)) { - *(size_t *)destc = *(size_t *)srcc; + destc += sizeof(size_t), + srcc += sizeof(size_t)) { + *(size_t*)destc = *(size_t*)srcc; } } @@ -40,7 +46,8 @@ void memcpy(void *dest, const void *src, size_t size) } } -void memmove(void *dest, const void *src, size_t size) +void +memmove(void* dest, const void* src, size_t size) { // memcpy does the job of moving backwards just fine if (dest < src || src + size <= dest) { @@ -48,8 +55,8 @@ void memmove(void *dest, const void *src, size_t size) } // Moving forward is just a reverse memcpy - char *destc = (char *)dest; - const char *srcc = (const char *)src; + char* destc = (char*)dest; + const char* srcc = (const char*)src; // If we can align both dest and src together... if ((uintptr_t)srcc % sizeof(size_t) == (uintptr_t)destc % sizeof(size_t)) { @@ -60,7 +67,7 @@ void memmove(void *dest, const void *src, size_t size) while (size >= sizeof(size_t)) { size -= sizeof(size_t); - *(size_t *)(destc + size) = *(size_t *)(srcc + size); + *(size_t*)(destc + size) = *(size_t*)(srcc + size); } } @@ -70,9 +77,10 @@ void memmove(void *dest, const void *src, size_t size) } } -void memset(void *dest, const int filler, size_t size) +void +memset(void* dest, const int filler, size_t size) { - char *destc = (char *)dest; + char* destc = (char*)dest; // Align dest to 4 bytes while ((uintptr_t)destc % sizeof(size_t) && size--) { @@ -80,8 +88,9 @@ void memset(void *dest, const int filler, size_t size) } // Set 32 bytes at a time - for (; size >= sizeof(size_t); size -= sizeof(size_t), destc += sizeof(size_t)) { - *(size_t *)destc = filler; + for (; size >= sizeof(size_t); + size -= sizeof(size_t), destc += sizeof(size_t)) { + *(size_t*)destc = filler; } // Finish @@ -90,10 +99,11 @@ void memset(void *dest, const int filler, size_t size) } } -int memcmp(const void *buf1, const void *buf2, const size_t size) +int +memcmp(const void* buf1, const void* buf2, const size_t size) { - const char *buf1c = (const char *)buf1; - const char *buf2c = (const char *)buf2; + const char* buf1c = (const char*)buf1; + const char* buf2c = (const char*)buf2; for (size_t i = 0; i < size; i++) { int cmp = buf1c[i] - buf2c[i]; if (cmp) { @@ -104,10 +114,11 @@ int memcmp(const void *buf1, const void *buf2, const size_t size) return 0; } -void strncpy(void *dest, const void *src, const size_t size) +void +strncpy(void* dest, const void* src, const size_t size) { - char *destc = (char *)dest; - const char *srcc = (const char *)src; + char* destc = (char*)dest; + const char* srcc = (const char*)src; size_t i; for (i = 0; i < size && srcc[i] != 0; i++) { @@ -118,10 +129,11 @@ void strncpy(void *dest, const void *src, const size_t size) destc[i] = 0; } -int strncmp(const void *buf1, const void *buf2, const size_t size) +int +strncmp(const void* buf1, const void* buf2, const size_t size) { - const char *buf1c = (const char *)buf1; - const char *buf2c = (const char *)buf2; + const char* buf1c = (const char*)buf1; + const char* buf2c = (const char*)buf2; size_t i; for (i = 0; i < size && buf1c[i] != 0 && buf2c[i] != 0; i++) { @@ -139,11 +151,12 @@ int strncmp(const void *buf1, const void *buf2, const size_t size) return 0; } -int atoi(const char *str) +int +atoi(const char* str) { int res = 0; while (*str && *str >= '0' && *str <= '9') { - res = *str - '0' + res * 10; + res = *str - '0' + res * 10; str++; } @@ -154,58 +167,69 @@ int atoi(const char *str) #define NOT_FOUND patlen #define max(a, b) ((a < b) ? b : a) -void make_delta1(int *delta1, uint8_t *pat, int32_t patlen) { +void +make_delta1(int* delta1, uint8_t* pat, int32_t patlen) +{ int i; - for (i=0; i < ALPHABET_LEN; i++) { + for (i = 0; i < ALPHABET_LEN; i++) { delta1[i] = NOT_FOUND; } - for (i=0; i < patlen-1; i++) { - delta1[pat[i]] = patlen-1 - i; + for (i = 0; i < patlen - 1; i++) { + delta1[pat[i]] = patlen - 1 - i; } } -int is_prefix(uint8_t *word, int wordlen, int pos) { +int +is_prefix(uint8_t* word, int wordlen, int pos) +{ int i; int suffixlen = wordlen - pos; // could also use the strncmp() library function here for (i = 0; i < suffixlen; i++) { - if (word[i] != word[pos+i]) { + if (word[i] != word[pos + i]) { return 0; } } return 1; } -int suffix_length(uint8_t *word, int wordlen, int pos) { +int +suffix_length(uint8_t* word, int wordlen, int pos) +{ int i; // increment suffix length i to the first mismatch or beginning // of the word - for (i = 0; (word[pos-i] == word[wordlen-1-i]) && (i < pos); i++); + for (i = 0; (word[pos - i] == word[wordlen - 1 - i]) && (i < pos); i++) + ; return i; } -void make_delta2(int *delta2, uint8_t *pat, int32_t patlen) { +void +make_delta2(int* delta2, uint8_t* pat, int32_t patlen) +{ int p; - int last_prefix_index = patlen-1; + int last_prefix_index = patlen - 1; // first loop - for (p=patlen-1; p>=0; p--) { - if (is_prefix(pat, patlen, p+1)) { - last_prefix_index = p+1; + for (p = patlen - 1; p >= 0; p--) { + if (is_prefix(pat, patlen, p + 1)) { + last_prefix_index = p + 1; } - delta2[p] = last_prefix_index + (patlen-1 - p); + delta2[p] = last_prefix_index + (patlen - 1 - p); } // second loop - for (p=0; p < patlen-1; p++) { + for (p = 0; p < patlen - 1; p++) { int slen = suffix_length(pat, patlen, p); - if (pat[p - slen] != pat[patlen-1 - slen]) { - delta2[patlen-1 - slen] = patlen-1 - p + slen; + if (pat[p - slen] != pat[patlen - 1 - slen]) { + delta2[patlen - 1 - slen] = patlen - 1 - p + slen; } } } -uint8_t* memfind (uint8_t *string, uint32_t stringlen, uint8_t *pat, uint32_t patlen) { +uint8_t* +memfind(uint8_t* string, uint32_t stringlen, uint8_t* pat, uint32_t patlen) +{ uint32_t i; int delta1[ALPHABET_LEN]; int delta2[ALPHABET_LEN]; // Max search length is 256. @@ -213,17 +237,18 @@ uint8_t* memfind (uint8_t *string, uint32_t stringlen, uint8_t *pat, uint32_t pa make_delta2(delta2, pat, patlen); // The empty pattern must be considered specially - if (patlen == 0) return string; + if (patlen == 0) + return string; - i = patlen-1; + i = patlen - 1; while (i < stringlen) { - int j = patlen-1; + int j = patlen - 1; while (j >= 0 && (string[i] == pat[j])) { --i; --j; } if (j < 0) { - return (string + i+1); + return (string + i + 1); } i += max(delta1[string[i]], delta2[j]); diff --git a/source/std/memory.h b/source/std/memory.h index 4afbc76..859115f 100644 --- a/source/std/memory.h +++ b/source/std/memory.h @@ -4,15 +4,16 @@ #include #include -int strlen(const char *string); -void memcpy(void *dest, const void *src, size_t size); -void memmove(void *dest, const void *src, size_t size); -void memset(void *dest, const int filler, size_t size); -int memcmp(const void *buf1, const void *buf2, const size_t size); -void strncpy(void *dest, const void *src, const size_t size); -int strncmp(const void *buf1, const void *buf2, const size_t size); -int atoi(const char *str); -uint8_t* memfind (uint8_t *string, uint32_t stringlen, uint8_t *pat, uint32_t patlen); +int strlen(const char* string); +void memcpy(void* dest, const void* src, size_t size); +void memmove(void* dest, const void* src, size_t size); +void memset(void* dest, const int filler, size_t size); +int memcmp(const void* buf1, const void* buf2, const size_t size); +void strncpy(void* dest, const void* src, const size_t size); +int strncmp(const void* buf1, const void* buf2, const size_t size); +int atoi(const char* str); +uint8_t* memfind(uint8_t* string, uint32_t stringlen, uint8_t* pat, + uint32_t patlen); int isprint(char c); #endif diff --git a/source/std/types.h b/source/std/types.h index 4e99217..cea64cf 100644 --- a/source/std/types.h +++ b/source/std/types.h @@ -4,8 +4,8 @@ #include #include -#define CFG_BOOTENV *(volatile uint32_t *)0x10010000 -#define HID ~*(volatile uint32_t *)0x10146000 +#define CFG_BOOTENV *(volatile uint32_t*)0x10010000 +#define HID ~*(volatile uint32_t*)0x10146000 #define PDN_MPCORE_CFG *(uint8_t*)0x10140FFC #endif