Upgrade fatfs and sdmmc driver

This commit is contained in:
TuxSH 2019-02-28 19:04:11 +01:00
parent f718297591
commit 710ad11819
12 changed files with 2044 additions and 1364 deletions

View File

@ -300,3 +300,31 @@ R0.13 (May 21, 2017)
Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c) Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c)
Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c) Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c)
R0.13a (October 14, 2017)
Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2)
Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF).
Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk().
Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09)
Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c)
Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12)
R0.13b (April 07, 2018)
Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3)
Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2)
Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c)
Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b)
R0.13c (October 14, 2018)
Supported stdint.h for C99 and later. (integer.h was included in ff.h)
Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12)
Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12)
Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b)

View File

@ -1,4 +1,4 @@
FatFs Module Source Files R0.13 FatFs Module Source Files R0.13c
FILES FILES
@ -10,7 +10,6 @@ FILES
ff.h Common include file for FatFs and application module. ff.h Common include file for FatFs and application module.
diskio.h Common include file for FatFs and disk I/O module. diskio.h Common include file for FatFs and disk I/O module.
diskio.c An example of glue function to attach existing disk I/O module to FatFs. diskio.c An example of glue function to attach existing disk I/O module to FatFs.
integer.h Integer type definitions for FatFs.
ffunicode.c Optional Unicode utility functions. ffunicode.c Optional Unicode utility functions.
ffsystem.c An example of optional O/S related functions. ffsystem.c An example of optional O/S related functions.

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13 / / FatFs - Generic FAT Filesystem module R0.13c /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2017, ChaN, all right reserved. / Copyright (C) 2018, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -20,13 +20,12 @@
#ifndef FF_DEFINED #ifndef FF_DEFINED
#define FF_DEFINED 87030 /* Revision ID */ #define FF_DEFINED 86604 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */ #include "ffconf.h" /* FatFs configuration options */
#if FF_DEFINED != FFCONF_DEF #if FF_DEFINED != FFCONF_DEF
@ -34,6 +33,30 @@ extern "C" {
#endif #endif
/* Integer types used for FatFs API */
#if defined(_WIN32) /* Main development platform */
#define FF_INTDEF 2
#include <windows.h>
typedef unsigned __int64 QWORD;
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
#define FF_INTDEF 2
#include <stdint.h>
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef uint16_t WORD; /* 16-bit unsigned integer */
typedef uint16_t WCHAR; /* 16-bit unsigned integer */
typedef uint32_t DWORD; /* 32-bit unsigned integer */
typedef uint64_t QWORD; /* 64-bit unsigned integer */
#else /* Earlier than C99 */
#define FF_INTDEF 1
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef unsigned short WORD; /* 16-bit unsigned integer */
typedef unsigned short WCHAR; /* 16-bit unsigned integer */
typedef unsigned long DWORD; /* 32-bit unsigned integer */
#endif
/* Definitions of volume management */ /* Definitions of volume management */
@ -45,24 +68,39 @@ typedef struct {
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#endif #endif
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
#endif
#endif
/* Type of path name strings on FatFs API */ /* Type of path name strings on FatFs API */
#if FF_LFN_UNICODE && FF_USE_LFN /* Unicode (UTF-16) string */
#ifndef _INC_TCHAR #ifndef _INC_TCHAR
#define _INC_TCHAR
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
typedef WCHAR TCHAR; typedef WCHAR TCHAR;
#define _T(x) L ## x #define _T(x) L ## x
#define _TEXT(x) L ## x #define _TEXT(x) L ## x
#define _INC_TCHAR #elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
#endif typedef char TCHAR;
#else /* ANSI/OEM string */ #define _T(x) u8 ## x
#ifndef _INC_TCHAR #define _TEXT(x) u8 ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
typedef DWORD TCHAR;
#define _T(x) U ## x
#define _TEXT(x) U ## x
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
#error Wrong FF_LFN_UNICODE setting
#else /* ANSI/OEM code in SBCS/DBCS */
typedef char TCHAR; typedef char TCHAR;
#define _T(x) x #define _T(x) x
#define _TEXT(x) x #define _TEXT(x) x
#define _INC_TCHAR
#endif #endif
#endif #endif
@ -70,8 +108,8 @@ typedef char TCHAR;
/* Type of file size variables */ /* Type of file size variables */
#if FF_FS_EXFAT #if FF_FS_EXFAT
#if !FF_USE_LFN #if FF_INTDEF != 2
#error LFN must be enabled when enable exFAT #error exFAT feature wants C99 or later
#endif #endif
typedef QWORD FSIZE_t; typedef QWORD FSIZE_t;
#else #else
@ -83,8 +121,8 @@ typedef DWORD FSIZE_t;
/* Filesystem object structure (FATFS) */ /* Filesystem object structure (FATFS) */
typedef struct { typedef struct {
BYTE fs_type; /* Filesystem type (0:N/A) */ BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Physical drive number */ BYTE pdrv; /* Associated physical drive */
BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
@ -121,6 +159,9 @@ typedef struct {
DWORD fatbase; /* FAT base sector */ DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */ DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */ DWORD database; /* Data base sector */
#if FF_FS_EXFAT
DWORD bitbase; /* Allocation bitmap base sector */
#endif
DWORD winsect; /* Current sector appearing in the win[] */ DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS; } FATFS;
@ -133,7 +174,7 @@ typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */ FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */ WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */ BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT #if FF_FS_EXFAT
@ -200,10 +241,10 @@ typedef struct {
WORD ftime; /* Modified time */ WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */ BYTE fattrib; /* File attribute */
#if FF_USE_LFN #if FF_USE_LFN
TCHAR altname[13]; /* Altenative file name */ TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
TCHAR fname[FF_MAX_LFN + 1]; /* Primary file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
#else #else
TCHAR fname[13]; /* File name */ TCHAR fname[12 + 1]; /* File name */
#endif #endif
} FILINFO; } FILINFO;
@ -299,10 +340,10 @@ DWORD get_fattime (void);
#endif #endif
/* LFN support functions */ /* LFN support functions */
#if FF_USE_LFN /* Code conversion (defined in unicode.c) */ #if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (WCHAR uni, WORD cp); /* Unicode to OEM code conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
WCHAR ff_wtoupper (WCHAR uni); /* Unicode upper-case conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
#endif #endif
#if FF_USE_LFN == 3 /* Dynamic memory allocation */ #if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */ void* ff_memalloc (UINT msize); /* Allocate memory block */

View File

@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - Configuration file / FatFs Functional Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define FFCONF_DEF 87030 /* Revision ID */ #define FFCONF_DEF 86604 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
@ -18,7 +18,7 @@
#define FF_FS_MINIMIZE 0 #define FF_FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions. /* This option defines minimization level to remove some basic API functions.
/ /
/ 0: All basic functions are enabled. / 0: Basic functions are fully enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ are removed. / are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
@ -106,32 +106,47 @@
/ 2: Enable LFN with dynamic working buffer on the STACK. / 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP. / 3: Enable LFN with dynamic working buffer on the HEAP.
/ /
/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
/ to the project. The working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/ additional 608 bytes at exFAT enabled. FF_MAX_LFN can be in range from 12 to 255. / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
/ It should be set 255 to support full featured LFN operations. / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN
/ specification.
/ When use stack for the working buffer, take care on stack overflow. When use heap / 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 / memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */ / ff_memfree() in ffsystem.c, need to be added to the project. */
#define FF_LFN_UNICODE 0 #define FF_LFN_UNICODE 2
/* This option switches character encoding on the API, 0:ANSI/OEM or 1:UTF-16, /* This option switches the character encoding on the API when LFN is enabled.
/ when LFN is enabled. Also behavior of string I/O functions will be affected by /
/ this option. When LFN is not enabled, this option has no effect. / 0: ANSI/OEM in current CP (TCHAR = char)
*/ / 1: Unicode in UTF-16 (TCHAR = WCHAR)
/ 2: Unicode in UTF-8 (TCHAR = char)
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
/
/ Also behavior of string I/O functions will be affected by this option.
/ When LFN is not enabled, this option has no effect. */
#define FF_LFN_BUF 255
#define FF_SFN_BUF 12
/* This set of options defines size of file name members in the FILINFO structure
/ which is used to read out directory items. These values should be suffcient for
/ the file names to read. The maximum possible length of the read file name depends
/ on character encoding. When LFN is not enabled, these options have no effect. */
#define FF_STRF_ENCODE 3 #define FF_STRF_ENCODE 3
/* When FF_LFN_UNICODE = 1 with LFN enabled, string I/O functions, f_gets(), /* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/ f_putc(), f_puts and f_printf() convert the character encoding in it. / f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be / This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions. / read/written via those functions.
/ /
/ 0: ANSI/OEM / 0: ANSI/OEM in current CP
/ 1: UTF-16LE / 1: Unicode in UTF-16LE
/ 2: UTF-16BE / 2: Unicode in UTF-16BE
/ 3: UTF-8 / 3: Unicode in UTF-8
*/ */
@ -154,11 +169,16 @@
#define FF_STR_VOLUME_ID 0 #define FF_STR_VOLUME_ID 0
#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* FF_STR_VOLUME_ID switches string support for volume ID. /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/ When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the drive ID strings for each / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
/ logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for / logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ the drive ID strings are: A-Z and 0-9. */ / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as:
/
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/
#define FF_MULTI_PARTITION 0 #define FF_MULTI_PARTITION 0
@ -212,17 +232,17 @@
#define FF_FS_EXFAT 0 #define FF_FS_EXFAT 0
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ When enable exFAT, also LFN needs to be enabled. / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ / Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define FF_FS_NORTC 1 #define FF_FS_NORTC 1
#define FF_NORTC_MON 5 #define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1 #define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2017 #define FF_NORTC_YEAR 2019
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp / the timestamp function. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON, / added to the project to read current time form real-time clock. FF_NORTC_MON,
@ -242,6 +262,7 @@
/ lock control is independent of re-entrancy. */ / lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0 #define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000 #define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE #define FF_SYNC_t HANDLE
@ -262,8 +283,6 @@
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */ / included somewhere in the scope of ff.h. */
/* #include <windows.h> // O/S definitions */
/*--- End of configuration options ---*/ /*--- End of configuration options ---*/

View File

@ -1,20 +1,19 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Sample code of OS dependent controls for FatFs */ /* Sample Code of OS Dependent Functions for FatFs */
/* (C)ChaN, 2017 */ /* (C)ChaN, 2018 */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include "ff.h" #include "ff.h"
#if FF_USE_LFN == 3 /* Dynamic memory allocation */ #if FF_USE_LFN == 3 /* Dynamic memory allocation */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Allocate a memory block */ /* Allocate a memory block */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */ UINT msize /* Number of bytes to allocate */
) )
{ {
@ -27,7 +26,7 @@ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on no
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
void ff_memfree ( void ff_memfree (
void* mblock /* Pointer to the memory block to free */ void* mblock /* Pointer to the memory block to free (nothing to do if null) */
) )
{ {
free(mblock); /* Free the memory block with POSIX API */ free(mblock); /* Free the memory block with POSIX API */
@ -47,12 +46,12 @@ void ff_memfree (
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR. / When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/ */
//const osMutexDef_t Mutex[FF_VOLUMES]; /* CMSIS-RTOS */ //const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
BYTE vol, /* Corresponding volume (logical drive number) */ BYTE vol, /* Corresponding volume (logical drive number) */
FF_SYNC_t *sobj /* Pointer to return the created sync object */ FF_SYNC_t* sobj /* Pointer to return the created sync object */
) )
{ {
/* Win32 */ /* Win32 */
@ -74,7 +73,7 @@ int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object
// return (int)(*sobj != NULL); // return (int)(*sobj != NULL);
/* CMSIS-RTOS */ /* CMSIS-RTOS */
// *sobj = osMutexCreate(Mutex + vol); // *sobj = osMutexCreate(&Mutex[vol]);
// return (int)(*sobj != NULL); // return (int)(*sobj != NULL);
} }

View File

@ -1,5 +1,5 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13+ */ /* Unicode handling functions for FatFs R0.13c */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the / /* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode / / FatFs is configured for LFN with DBCS. If the system has any Unicode /
@ -7,7 +7,7 @@
/ that function to avoid silly memory consumption. / / that function to avoid silly memory consumption. /
/-------------------------------------------------------------------------*/ /-------------------------------------------------------------------------*/
/* /*
/ Copyright (C) 2017, ChaN, all right reserved. / Copyright (C) 2018, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -25,7 +25,11 @@
#include "ff.h" #include "ff.h"
#if FF_USE_LFN #if FF_USE_LFN /* This module will be blanked at non-LFN configuration */
#if FF_DEFINED != 86604 /* Revision ID */
#error Wrong include file (ff.h).
#endif
#define MERGE2(a, b) a ## b #define MERGE2(a, b) a ## b
#define CVTBL(tbl, cp) MERGE2(tbl, cp) #define CVTBL(tbl, cp) MERGE2(tbl, cp)
@ -36,8 +40,7 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE == 932 || FF_CODE_PAGE == 0 /* Japanese */ #if FF_CODE_PAGE == 932 || FF_CODE_PAGE == 0 /* Japanese */
static static const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */
const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */
0x00A7, 0x8198, 0x00A8, 0x814E, 0x00B0, 0x818B, 0x00B1, 0x817D, 0x00B4, 0x814C, 0x00B6, 0x81F7, 0x00D7, 0x817E, 0x00F7, 0x8180, 0x00A7, 0x8198, 0x00A8, 0x814E, 0x00B0, 0x818B, 0x00B1, 0x817D, 0x00B4, 0x814C, 0x00B6, 0x81F7, 0x00D7, 0x817E, 0x00F7, 0x8180,
0x0391, 0x839F, 0x0392, 0x83A0, 0x0393, 0x83A1, 0x0394, 0x83A2, 0x0395, 0x83A3, 0x0396, 0x83A4, 0x0397, 0x83A5, 0x0398, 0x83A6, 0x0391, 0x839F, 0x0392, 0x83A0, 0x0393, 0x83A1, 0x0394, 0x83A2, 0x0395, 0x83A3, 0x0396, 0x83A4, 0x0397, 0x83A5, 0x0398, 0x83A6,
0x0399, 0x83A7, 0x039A, 0x83A8, 0x039B, 0x83A9, 0x039C, 0x83AA, 0x039D, 0x83AB, 0x039E, 0x83AC, 0x039F, 0x83AD, 0x03A0, 0x83AE, 0x0399, 0x83A7, 0x039A, 0x83A8, 0x039B, 0x83A9, 0x039C, 0x83AA, 0x039D, 0x83AB, 0x039E, 0x83AC, 0x039F, 0x83AD, 0x03A0, 0x83AE,
@ -964,8 +967,7 @@ const WCHAR uni2oem932[] = { /* Unicode --> Shift_JIS pairs */
0xFFE1, 0x8192, 0xFFE2, 0x81CA, 0xFFE3, 0x8150, 0xFFE4, 0xFA55, 0xFFE5, 0x818F, 0, 0 0xFFE1, 0x8192, 0xFFE2, 0x81CA, 0xFFE3, 0x8150, 0xFFE4, 0xFA55, 0xFFE5, 0x818F, 0, 0
}; };
static static const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */
const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */
0x00A1, 0xFF61, 0x00A2, 0xFF62, 0x00A3, 0xFF63, 0x00A4, 0xFF64, 0x00A5, 0xFF65, 0x00A6, 0xFF66, 0x00A7, 0xFF67, 0x00A8, 0xFF68, 0x00A1, 0xFF61, 0x00A2, 0xFF62, 0x00A3, 0xFF63, 0x00A4, 0xFF64, 0x00A5, 0xFF65, 0x00A6, 0xFF66, 0x00A7, 0xFF67, 0x00A8, 0xFF68,
0x00A9, 0xFF69, 0x00AA, 0xFF6A, 0x00AB, 0xFF6B, 0x00AC, 0xFF6C, 0x00AD, 0xFF6D, 0x00AE, 0xFF6E, 0x00AF, 0xFF6F, 0x00B0, 0xFF70, 0x00A9, 0xFF69, 0x00AA, 0xFF6A, 0x00AB, 0xFF6B, 0x00AC, 0xFF6C, 0x00AD, 0xFF6D, 0x00AE, 0xFF6E, 0x00AF, 0xFF6F, 0x00B0, 0xFF70,
0x00B1, 0xFF71, 0x00B2, 0xFF72, 0x00B3, 0xFF73, 0x00B4, 0xFF74, 0x00B5, 0xFF75, 0x00B6, 0xFF76, 0x00B7, 0xFF77, 0x00B8, 0xFF78, 0x00B1, 0xFF71, 0x00B2, 0xFF72, 0x00B3, 0xFF73, 0x00B4, 0xFF74, 0x00B5, 0xFF75, 0x00B6, 0xFF76, 0x00B7, 0xFF77, 0x00B8, 0xFF78,
@ -1894,8 +1896,7 @@ const WCHAR oem2uni932[] = { /* Shift_JIS --> Unicode pairs */
#endif #endif
#if FF_CODE_PAGE == 936 || FF_CODE_PAGE == 0 /* Simplified Chinese */ #if FF_CODE_PAGE == 936 || FF_CODE_PAGE == 0 /* Simplified Chinese */
static static const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */
const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */
0x00A4, 0xA1E8, 0x00A7, 0xA1EC, 0x00A8, 0xA1A7, 0x00B0, 0xA1E3, 0x00B1, 0xA1C0, 0x00B7, 0xA1A4, 0x00D7, 0xA1C1, 0x00E0, 0xA8A4, 0x00A4, 0xA1E8, 0x00A7, 0xA1EC, 0x00A8, 0xA1A7, 0x00B0, 0xA1E3, 0x00B1, 0xA1C0, 0x00B7, 0xA1A4, 0x00D7, 0xA1C1, 0x00E0, 0xA8A4,
0x00E1, 0xA8A2, 0x00E8, 0xA8A8, 0x00E9, 0xA8A6, 0x00EA, 0xA8BA, 0x00EC, 0xA8AC, 0x00ED, 0xA8AA, 0x00F2, 0xA8B0, 0x00F3, 0xA8AE, 0x00E1, 0xA8A2, 0x00E8, 0xA8A8, 0x00E9, 0xA8A6, 0x00EA, 0xA8BA, 0x00EC, 0xA8AC, 0x00ED, 0xA8AA, 0x00F2, 0xA8B0, 0x00F3, 0xA8AE,
0x00F7, 0xA1C2, 0x00F9, 0xA8B4, 0x00FA, 0xA8B2, 0x00FC, 0xA8B9, 0x0101, 0xA8A1, 0x0113, 0xA8A5, 0x011B, 0xA8A7, 0x012B, 0xA8A9, 0x00F7, 0xA1C2, 0x00F9, 0xA8B4, 0x00FA, 0xA8B2, 0x00FC, 0xA8B9, 0x0101, 0xA8A1, 0x0113, 0xA8A5, 0x011B, 0xA8A7, 0x012B, 0xA8A9,
@ -4623,8 +4624,7 @@ const WCHAR uni2oem936[] = { /* Unicode --> GBK pairs */
0, 0 0, 0
}; };
static static const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */
const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */
0x0080, 0x20AC, 0x8140, 0x4E02, 0x8141, 0x4E04, 0x8142, 0x4E05, 0x8143, 0x4E06, 0x8144, 0x4E0F, 0x8145, 0x4E12, 0x8146, 0x4E17, 0x0080, 0x20AC, 0x8140, 0x4E02, 0x8141, 0x4E04, 0x8142, 0x4E05, 0x8143, 0x4E06, 0x8144, 0x4E0F, 0x8145, 0x4E12, 0x8146, 0x4E17,
0x8147, 0x4E1F, 0x8148, 0x4E20, 0x8149, 0x4E21, 0x814A, 0x4E23, 0x814B, 0x4E26, 0x814C, 0x4E29, 0x814D, 0x4E2E, 0x814E, 0x4E2F, 0x8147, 0x4E1F, 0x8148, 0x4E20, 0x8149, 0x4E21, 0x814A, 0x4E23, 0x814B, 0x4E26, 0x814C, 0x4E29, 0x814D, 0x4E2E, 0x814E, 0x4E2F,
0x814F, 0x4E31, 0x8150, 0x4E33, 0x8151, 0x4E35, 0x8152, 0x4E37, 0x8153, 0x4E3C, 0x8154, 0x4E40, 0x8155, 0x4E41, 0x8156, 0x4E42, 0x814F, 0x4E31, 0x8150, 0x4E33, 0x8151, 0x4E35, 0x8152, 0x4E37, 0x8153, 0x4E3C, 0x8154, 0x4E40, 0x8155, 0x4E41, 0x8156, 0x4E42,
@ -7354,8 +7354,7 @@ const WCHAR oem2uni936[] = { /* GBK --> Unicode pairs */
#endif #endif
#if FF_CODE_PAGE == 949 || FF_CODE_PAGE == 0 /* Korean */ #if FF_CODE_PAGE == 949 || FF_CODE_PAGE == 0 /* Korean */
static static const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */
const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */
0x00A1, 0xA2AE, 0x00A4, 0xA2B4, 0x00A7, 0xA1D7, 0x00A8, 0xA1A7, 0x00AA, 0xA8A3, 0x00AD, 0xA1A9, 0x00AE, 0xA2E7, 0x00B0, 0xA1C6, 0x00A1, 0xA2AE, 0x00A4, 0xA2B4, 0x00A7, 0xA1D7, 0x00A8, 0xA1A7, 0x00AA, 0xA8A3, 0x00AD, 0xA1A9, 0x00AE, 0xA2E7, 0x00B0, 0xA1C6,
0x00B1, 0xA1BE, 0x00B2, 0xA9F7, 0x00B3, 0xA9F8, 0x00B4, 0xA2A5, 0x00B6, 0xA2D2, 0x00B7, 0xA1A4, 0x00B8, 0xA2AC, 0x00B9, 0xA9F6, 0x00B1, 0xA1BE, 0x00B2, 0xA9F7, 0x00B3, 0xA9F8, 0x00B4, 0xA2A5, 0x00B6, 0xA2D2, 0x00B7, 0xA1A4, 0x00B8, 0xA2AC, 0x00B9, 0xA9F6,
0x00BA, 0xA8AC, 0x00BC, 0xA8F9, 0x00BD, 0xA8F6, 0x00BE, 0xA8FA, 0x00BF, 0xA2AF, 0x00C6, 0xA8A1, 0x00D0, 0xA8A2, 0x00D7, 0xA1BF, 0x00BA, 0xA8AC, 0x00BC, 0xA8F9, 0x00BD, 0xA8F6, 0x00BE, 0xA8FA, 0x00BF, 0xA2AF, 0x00C6, 0xA8A1, 0x00D0, 0xA8A2, 0x00D7, 0xA1BF,
@ -9490,8 +9489,7 @@ const WCHAR uni2oem949[] = { /* Unicode --> Korean pairs */
0, 0 0, 0
}; };
static static const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */
const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */
0x8141, 0xAC02, 0x8142, 0xAC03, 0x8143, 0xAC05, 0x8144, 0xAC06, 0x8145, 0xAC0B, 0x8146, 0xAC0C, 0x8147, 0xAC0D, 0x8148, 0xAC0E, 0x8141, 0xAC02, 0x8142, 0xAC03, 0x8143, 0xAC05, 0x8144, 0xAC06, 0x8145, 0xAC0B, 0x8146, 0xAC0C, 0x8147, 0xAC0D, 0x8148, 0xAC0E,
0x8149, 0xAC0F, 0x814A, 0xAC18, 0x814B, 0xAC1E, 0x814C, 0xAC1F, 0x814D, 0xAC21, 0x814E, 0xAC22, 0x814F, 0xAC23, 0x8150, 0xAC25, 0x8149, 0xAC0F, 0x814A, 0xAC18, 0x814B, 0xAC1E, 0x814C, 0xAC1F, 0x814D, 0xAC21, 0x814E, 0xAC22, 0x814F, 0xAC23, 0x8150, 0xAC25,
0x8151, 0xAC26, 0x8152, 0xAC27, 0x8153, 0xAC28, 0x8154, 0xAC29, 0x8155, 0xAC2A, 0x8156, 0xAC2B, 0x8157, 0xAC2E, 0x8158, 0xAC32, 0x8151, 0xAC26, 0x8152, 0xAC27, 0x8153, 0xAC28, 0x8154, 0xAC29, 0x8155, 0xAC2A, 0x8156, 0xAC2B, 0x8157, 0xAC2E, 0x8158, 0xAC32,
@ -11628,8 +11626,7 @@ const WCHAR oem2uni949[] = { /* Korean --> Unicode pairs */
#endif #endif
#if FF_CODE_PAGE == 950 || FF_CODE_PAGE == 0 /* Traditional Chinese */ #if FF_CODE_PAGE == 950 || FF_CODE_PAGE == 0 /* Traditional Chinese */
static static const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */
const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */
0x00A7, 0xA1B1, 0x00AF, 0xA1C2, 0x00B0, 0xA258, 0x00B1, 0xA1D3, 0x00B7, 0xA150, 0x00D7, 0xA1D1, 0x00F7, 0xA1D2, 0x02C7, 0xA3BE, 0x00A7, 0xA1B1, 0x00AF, 0xA1C2, 0x00B0, 0xA258, 0x00B1, 0xA1D3, 0x00B7, 0xA150, 0x00D7, 0xA1D1, 0x00F7, 0xA1D2, 0x02C7, 0xA3BE,
0x02C9, 0xA3BC, 0x02CA, 0xA3BD, 0x02CB, 0xA3BF, 0x02CD, 0xA1C5, 0x02D9, 0xA3BB, 0x0391, 0xA344, 0x0392, 0xA345, 0x0393, 0xA346, 0x02C9, 0xA3BC, 0x02CA, 0xA3BD, 0x02CB, 0xA3BF, 0x02CD, 0xA1C5, 0x02D9, 0xA3BB, 0x0391, 0xA344, 0x0392, 0xA345, 0x0393, 0xA346,
0x0394, 0xA347, 0x0395, 0xA348, 0x0396, 0xA349, 0x0397, 0xA34A, 0x0398, 0xA34B, 0x0399, 0xA34C, 0x039A, 0xA34D, 0x039B, 0xA34E, 0x0394, 0xA347, 0x0395, 0xA348, 0x0396, 0xA349, 0x0397, 0xA34A, 0x0398, 0xA34B, 0x0399, 0xA34C, 0x039A, 0xA34D, 0x039B, 0xA34E,
@ -13320,8 +13317,7 @@ const WCHAR uni2oem950[] = { /* Unicode --> Big5 pairs */
0xFF5C, 0xA155, 0xFF5D, 0xA162, 0xFF5E, 0xA1E3, 0xFFE0, 0xA246, 0xFFE1, 0xA247, 0xFFE3, 0xA1C3, 0xFFE5, 0xA244, 0, 0 0xFF5C, 0xA155, 0xFF5D, 0xA162, 0xFF5E, 0xA1E3, 0xFFE0, 0xA246, 0xFFE1, 0xA247, 0xFFE3, 0xA1C3, 0xFFE5, 0xA244, 0, 0
}; };
static static const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */
const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */
0xA140, 0x3000, 0xA141, 0xFF0C, 0xA142, 0x3001, 0xA143, 0x3002, 0xA144, 0xFF0E, 0xA145, 0x2027, 0xA146, 0xFF1B, 0xA147, 0xFF1A, 0xA140, 0x3000, 0xA141, 0xFF0C, 0xA142, 0x3001, 0xA143, 0x3002, 0xA144, 0xFF0E, 0xA145, 0x2027, 0xA146, 0xFF1B, 0xA147, 0xFF1A,
0xA148, 0xFF1F, 0xA149, 0xFF01, 0xA14A, 0xFE30, 0xA14B, 0x2026, 0xA14C, 0x2025, 0xA14D, 0xFE50, 0xA14E, 0xFE51, 0xA14F, 0xFE52, 0xA148, 0xFF1F, 0xA149, 0xFF01, 0xA14A, 0xFE30, 0xA14B, 0x2026, 0xA14C, 0x2025, 0xA14D, 0xFE50, 0xA14E, 0xFE51, 0xA14F, 0xFE52,
0xA150, 0x00B7, 0xA151, 0xFE54, 0xA152, 0xFE55, 0xA153, 0xFE56, 0xA154, 0xFE57, 0xA155, 0xFF5C, 0xA156, 0x2013, 0xA157, 0xFE31, 0xA150, 0x00B7, 0xA151, 0xFE54, 0xA152, 0xFE55, 0xA153, 0xFE56, 0xA154, 0xFE57, 0xA155, 0xFF5C, 0xA156, 0x2013, 0xA157, 0xFE31,
@ -15014,8 +15010,7 @@ const WCHAR oem2uni950[] = { /* Big5 --> Unicode pairs */
#endif #endif
#if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 437 || FF_CODE_PAGE == 0
static static const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 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, 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, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15027,8 +15022,7 @@ const WCHAR uc437[] = { /* CP437(U.S.) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 720 || FF_CODE_PAGE == 0
static static const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
@ -15040,8 +15034,7 @@ const WCHAR uc720[] = { /* CP720(Arabic) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 737 || FF_CODE_PAGE == 0
static static const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
@ -15053,8 +15046,7 @@ const WCHAR uc737[] = { /* CP737(Greek) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 771 || FF_CODE_PAGE == 0
static static const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
@ -15066,8 +15058,7 @@ const WCHAR uc771[] = { /* CP771(KBL) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 775 || FF_CODE_PAGE == 0
static static const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
@ -15079,8 +15070,7 @@ const WCHAR uc775[] = { /* CP775(Baltic) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 850 || FF_CODE_PAGE == 0
static static const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 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, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15092,8 +15082,7 @@ const WCHAR uc850[] = { /* CP850(Latin 1) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 852 || FF_CODE_PAGE == 0
static static const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
@ -15105,8 +15094,7 @@ const WCHAR uc852[] = { /* CP852(Latin 2) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 855 || FF_CODE_PAGE == 0
static static const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */
const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
@ -15118,8 +15106,7 @@ const WCHAR uc855[] = { /* CP855(Cyrillic) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 857 || FF_CODE_PAGE == 0
static static const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15131,8 +15118,7 @@ const WCHAR uc857[] = { /* CP857(Turkish) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 860 || FF_CODE_PAGE == 0
static static const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */
const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15144,8 +15130,7 @@ const WCHAR uc860[] = { /* CP860(Portuguese) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 861 || FF_CODE_PAGE == 0
static static const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */
const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15157,8 +15142,7 @@ const WCHAR uc861[] = { /* CP861(Icelandic) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 862 || FF_CODE_PAGE == 0
static static const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
@ -15170,8 +15154,7 @@ const WCHAR uc862[] = { /* CP862(Hebrew) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 863 || FF_CODE_PAGE == 0
static static const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */
const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
@ -15183,8 +15166,7 @@ const WCHAR uc863[] = { /* CP863(Canadian French) to Unicode conversion table *
}; };
#endif #endif
#if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 864 || FF_CODE_PAGE == 0
static static const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
@ -15196,8 +15178,7 @@ const WCHAR uc864[] = { /* CP864(Arabic) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 865 || FF_CODE_PAGE == 0
static static const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
@ -15209,8 +15190,7 @@ const WCHAR uc865[] = { /* CP865(Nordic) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 866 || FF_CODE_PAGE == 0
static static const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
@ -15222,8 +15202,7 @@ const WCHAR uc866[] = { /* CP866(Russian) to Unicode conversion table */
}; };
#endif #endif
#if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 869 || FF_CODE_PAGE == 0
static static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
@ -15245,7 +15224,7 @@ const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WCHAR uni, /* Unicode character to be converted */ DWORD uni, /* UTF-16 encoded character to be converted */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
@ -15253,15 +15232,16 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR *p = CVTBL(uc, FF_CODE_PAGE);
if (uni < 0x80) { /* ASCII char */ if (uni < 0x80) { /* ASCII? */
c = uni; c = (WCHAR)uni;
} else { /* Non-ASCII char */ } else { /* Non-ASCII */
if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */
for (c = 0; c < 0x80 && uni != p[c]; c++) ; for (c = 0; c < 0x80 && uni != p[c]; c++) ;
c = (c + 0x80) & 0xFF; c = (c + 0x80) & 0xFF;
} }
} }
return c; return c;
} }
@ -15274,7 +15254,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR *p = CVTBL(uc, FF_CODE_PAGE);
if (oem < 0x80) { /* ASCII char */ if (oem < 0x80) { /* ASCII? */
c = oem; c = oem;
} else { /* Extended char */ } else { /* Extended char */
@ -15282,6 +15262,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
if (oem < 0x100) c = p[oem - 0x80]; if (oem < 0x100) c = p[oem - 0x80];
} }
} }
return c; return c;
} }
@ -15294,29 +15275,30 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
/* DBCS fixed code page */ /* DBCS fixed code page */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE != 0 && FF_CODE_PAGE >= 900 #if FF_CODE_PAGE >= 900
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WCHAR uni, /* Unicode character to be converted */ DWORD uni, /* UTF-16 encoded character to be converted */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR *p;
WCHAR c = 0; WCHAR c = 0, uc;
UINT i, n, li, hi; UINT i = 0, n, li, hi;
if (uni < 0x80) { /* ASCII char */ if (uni < 0x80) { /* ASCII? */
c = uni; c = (WCHAR)uni;
} else { /* Non-ASCII char */ } else { /* Non-ASCII */
if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ if (uni < 0x10000 && cp == FF_CODE_PAGE) { /* Is it in BMP and valid code page? */
uc = (WCHAR)uni;
p = CVTBL(uni2oem, FF_CODE_PAGE); p = CVTBL(uni2oem, FF_CODE_PAGE);
hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1; hi = sizeof CVTBL(uni2oem, FF_CODE_PAGE) / 4 - 1;
li = 0; li = 0;
for (n = 16; n; n--) { for (n = 16; n; n--) {
i = li + (hi - li) / 2; i = li + (hi - li) / 2;
if (uni == p[i * 2]) break; if (uc == p[i * 2]) break;
if (uni > p[i * 2]) { if (uc > p[i * 2]) {
li = i; li = i;
} else { } else {
hi = i; hi = i;
@ -15325,6 +15307,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
if (n != 0) c = p[i * 2 + 1]; if (n != 0) c = p[i * 2 + 1];
} }
} }
return c; return c;
} }
@ -15336,14 +15319,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
{ {
const WCHAR *p; const WCHAR *p;
WCHAR c = 0; WCHAR c = 0;
UINT i, n, li, hi; UINT i = 0, n, li, hi;
if (oem < 0x80) { /* ASCII char */ if (oem < 0x80) { /* ASCII? */
c = oem; c = oem;
} else { /* Extended char */ } else { /* Extended char */
if (cp == FF_CODE_PAGE) { /* Is it a valid code page? */ if (cp == FF_CODE_PAGE) { /* Is it valid code page? */
p = CVTBL(oem2uni, FF_CODE_PAGE); p = CVTBL(oem2uni, FF_CODE_PAGE);
hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1; hi = sizeof CVTBL(oem2uni, FF_CODE_PAGE) / 4 - 1;
li = 0; li = 0;
@ -15359,6 +15342,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
if (n != 0) c = p[i * 2 + 1]; if (n != 0) c = p[i * 2 + 1];
} }
} }
return c; return c;
} }
#endif #endif
@ -15372,59 +15356,63 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
#if FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 0
static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; static const WORD cp_code[] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0};
static const WCHAR *const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0}; static const WCHAR* const cp_table[] = {uc437, uc720, uc737, uc771, uc775, uc850, uc852, uc855, uc857, uc860, uc861, uc862, uc863, uc864, uc865, uc866, uc869, 0};
WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WCHAR uni, /* Unicode character to be converted */ DWORD uni, /* UTF-16 encoded character to be converted */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR *p;
WCHAR c = 0; WCHAR c = 0, uc;
UINT i, n, li, hi; UINT i, n, li, hi;
if (uni < 0x80) { /* ASCII char */ if (uni < 0x80) { /* ASCII? */
c = uni; c = (WCHAR)uni;
} else { /* Non-ASCII char */ } else { /* Non-ASCII */
p = 0; if (uni < 0x10000) { /* Is it in BMP? */
if (cp < 900) { /* SBCS */ uc = (WCHAR)uni;
for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get table */ p = 0;
p = cp_table[i]; if (cp < 900) { /* SBCS */
if (p) { /* Is it a valid CP ? */ for (i = 0; cp_code[i] != 0 && cp_code[i] != cp; i++) ; /* Get conversion table */
for (c = 0; c < 0x80 && uni != p[c]; c++) ; /* Find OEM code in the table */ p = cp_table[i];
c = (c + 0x80) & 0xFF; if (p) { /* Is it valid code page ? */
} for (c = 0; c < 0x80 && uc != p[c]; c++) ; /* Find OEM code in the table */
} else { /* DBCS */ c = (c + 0x80) & 0xFF;
switch (cp) { }
case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break; } else { /* DBCS */
case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break; switch (cp) { /* Get conversion table */
case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break; case 932 : p = uni2oem932; hi = sizeof uni2oem932 / 4 - 1; break;
case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break; case 936 : p = uni2oem936; hi = sizeof uni2oem936 / 4 - 1; break;
} case 949 : p = uni2oem949; hi = sizeof uni2oem949 / 4 - 1; break;
if (p) { /* Is it a valid code page? */ case 950 : p = uni2oem950; hi = sizeof uni2oem950 / 4 - 1; break;
li = 0; }
for (n = 16; n; n--) { /* Find OEM code */ if (p) { /* Is it valid code page? */
i = li + (hi - li) / 2; li = 0;
if (uni == p[i * 2]) break; for (n = 16; n; n--) { /* Find OEM code */
if (uni > p[i * 2]) { i = li + (hi - li) / 2;
li = i; if (uc == p[i * 2]) break;
} else { if (uc > p[i * 2]) {
hi = i; li = i;
} } else {
hi = i;
}
}
if (n != 0) c = p[i * 2 + 1];
} }
if (n != 0) c = p[i * 2 + 1];
} }
} }
} }
return c; return c;
} }
WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
WCHAR oem, /* OEM code to be converted */ WCHAR oem, /* OEM code to be converted (DBC if >=0x100) */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
@ -15433,7 +15421,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
UINT i, n, li, hi; UINT i, n, li, hi;
if (oem < 0x80) { /* ASCII char */ if (oem < 0x80) { /* ASCII? */
c = oem; c = oem;
} else { /* Extended char */ } else { /* Extended char */
@ -15466,6 +15454,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
} }
} }
} }
return c; return c;
} }
#endif #endif
@ -15476,54 +15465,94 @@ WCHAR ff_oem2uni ( /* Returns Unicode character, zero on error */
/* Unicode up-case conversion */ /* Unicode up-case conversion */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
WCHAR ff_wtoupper ( /* Returns up-converted character */ DWORD ff_wtoupper ( /* Returns up-converted code point */
WCHAR uni /* Unicode character to be upper converted (BMP only) */ DWORD uni /* Unicode code point to be up-converted */
) )
{ {
/* Compressed upper conversion table */ const WORD *p;
static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ WORD uc, bc, nc, cmd;
static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */
/* Basic Latin */ /* Basic Latin */
0x0061,0x031A, 0x0061,0x031A,
/* Latin-1 Supplement */ /* Latin-1 Supplement */
0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, 0x00E0,0x0317,
0x00F8,0x0307,
0x00FF,0x0001,0x0178,
/* Latin Extended-A */ /* Latin Extended-A */
0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, 0x0100,0x0130,
0x0132,0x0106,
0x0139,0x0110,
0x014A,0x012E,
0x0179,0x0106,
/* Latin Extended-B */ /* Latin Extended-B */
0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,
0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, 0x01CD,0x0110,
0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, 0x01DD,0x0001,0x018E,
0x01DE,0x0112,
0x01F3,0x0003,0x01F1,0x01F4,0x01F4,
0x01F8,0x0128,
0x0222,0x0112,
0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241,
0x0246,0x010A,
/* IPA Extensions */ /* IPA Extensions */
0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,
/* Greek, Coptic */ /* Greek, Coptic */
0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, 0x037B,0x0003,0x03FD,0x03FE,0x03FF,
0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A,
0x03B1,0x0311,
0x03C2,0x0002,0x03A3,0x03A3,
0x03C4,0x0308,
0x03CC,0x0003,0x038C,0x038E,0x038F,
0x03D8,0x0118,
0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,
/* Cyrillic */ /* Cyrillic */
0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, 0x0430,0x0320,
0x0450,0x0710,
0x0460,0x0122,
0x048A,0x0136,
0x04C1,0x010E,
0x04CF,0x0001,0x04C0,
0x04D0,0x0144,
/* Armenian */ /* Armenian */
0x0561,0x0426, 0x0561,0x0426,
0x0000 0x0000 /* EOT */
}; };
static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ static const WORD cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */
/* Phonetic Extensions */ /* Phonetic Extensions */
0x1D7D,0x0001,0x2C63, 0x1D7D,0x0001,0x2C63,
/* Latin Extended Additional */ /* Latin Extended Additional */
0x1E00,0x0196, 0x1EA0,0x015A, 0x1E00,0x0196,
0x1EA0,0x015A,
/* Greek Extended */ /* Greek Extended */
0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, 0x1F00,0x0608,
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, 0x1F10,0x0606,
0x1F20,0x0608,
0x1F30,0x0608,
0x1F40,0x0606,
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F,
0x1F60,0x0608,
0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,
0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, 0x1F80,0x0608,
0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF3,0x0001,0x1FFC, 0x1F90,0x0608,
0x1FA0,0x0608,
0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
0x1FCC,0x0001,0x1FC3,
0x1FD0,0x0602,
0x1FE0,0x0602,
0x1FE5,0x0001,0x1FEC,
0x1FF3,0x0001,0x1FFC,
/* Letterlike Symbols */ /* Letterlike Symbols */
0x214E,0x0001,0x2132, 0x214E,0x0001,0x2132,
/* Number forms */ /* Number forms */
0x2170,0x0210, 0x2184,0x0001,0x2183, 0x2170,0x0210,
0x2184,0x0001,0x2183,
/* Enclosed Alphanumerics */ /* Enclosed Alphanumerics */
0x24D0,0x051A, 0x2C30,0x042F, 0x24D0,0x051A,
0x2C30,0x042F,
/* Latin Extended-C */ /* Latin Extended-C */
0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, 0x2C60,0x0102,
0x2C67,0x0106, 0x2C75,0x0102,
/* Coptic */ /* Coptic */
0x2C80,0x0164, 0x2C80,0x0164,
/* Georgian Supplement */ /* Georgian Supplement */
@ -15531,36 +15560,38 @@ WCHAR ff_wtoupper ( /* Returns up-converted character */
/* Full-width */ /* Full-width */
0xFF41,0x031A, 0xFF41,0x031A,
0x0000 0x0000 /* EOT */
}; };
const WCHAR *p;
WCHAR bc, nc, cmd;
p = uni < 0x1000 ? cvt1 : cvt2; if (uni < 0x10000) { /* Is it in BMP? */
for (;;) { uc = (WORD)uni;
bc = *p++; /* Get block base */ p = uc < 0x1000 ? cvt1 : cvt2;
if (!bc || uni < bc) break; for (;;) {
nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ bc = *p++; /* Get the block base */
if (uni < bc + nc) { /* In the block? */ if (bc == 0 || uc < bc) break; /* Not matched? */
switch (cmd) { nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */
case 0: uni = p[uni - bc]; break; /* Table conversion */ if (uc < bc + nc) { /* In the block? */
case 1: uni -= (uni - bc) & 1; break; /* Case pairs */ switch (cmd) {
case 2: uni -= 16; break; /* Shift -16 */ case 0: uc = p[uc - bc]; break; /* Table conversion */
case 3: uni -= 32; break; /* Shift -32 */ case 1: uc -= (uc - bc) & 1; break; /* Case pairs */
case 4: uni -= 48; break; /* Shift -48 */ case 2: uc -= 16; break; /* Shift -16 */
case 5: uni -= 26; break; /* Shift -26 */ case 3: uc -= 32; break; /* Shift -32 */
case 6: uni += 8; break; /* Shift +8 */ case 4: uc -= 48; break; /* Shift -48 */
case 7: uni -= 80; break; /* Shift -80 */ case 5: uc -= 26; break; /* Shift -26 */
case 8: uni -= 0x1C60; break; /* Shift -0x1C60 */ case 6: uc += 8; break; /* Shift +8 */
case 7: uc -= 80; break; /* Shift -80 */
case 8: uc -= 0x1C60; break; /* Shift -0x1C60 */
}
break;
} }
break; if (cmd == 0) p += nc; /* Skip table if needed */
} }
if (!cmd) p += nc; uni = uc;
} }
return uni; return uni;
} }
#endif /* #if _USE_LFN */ #endif /* #if FF_USE_LFN */

View File

@ -1,16 +0,0 @@
.text
.arm
.align 4
.global waitcycles
.type waitcycles, %function
waitcycles:
push {r0-r2, lr}
str r0, [sp, #4]
waitcycles_loop:
ldr r3, [sp, #4]
subs r2, r3, #1
str r2, [sp, #4]
cmp r3, #0
bne waitcycles_loop
pop {r0-r2, pc}

View File

@ -1,6 +1,6 @@
/* /*
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file, * License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. * You can obtain one at http://mozilla.org/MPL/2.0/.
* *
* Copyright (c) 2014-2015, Normmatt * Copyright (c) 2014-2015, Normmatt
@ -22,143 +22,189 @@
* along with this program. If not, see http://www.gnu.org/licenses/. * along with this program. If not, see http://www.gnu.org/licenses/.
*/ */
#include <stdint.h>
#include <stdbool.h>
#include "wait_cycles.h"
#include "sdmmc.h" #include "sdmmc.h"
#include "delay.h"
static struct mmcdevice handleNAND; #define DATA32_SUPPORT
static struct mmcdevice handleSD;
static inline u16 sdmmc_read16(u16 reg)
{
return *(vu16 *)(SDMMC_BASE + reg);
}
static inline void sdmmc_write16(u16 reg, u16 val) struct mmcdevice handleNAND;
{ struct mmcdevice handleSD;
*(vu16 *)(SDMMC_BASE + reg) = val;
}
static inline u32 sdmmc_read32(u16 reg)
{
return *(vu32 *)(SDMMC_BASE + reg);
}
static inline void sdmmc_write32(u16 reg, u32 val)
{
*(vu32 *)(SDMMC_BASE + reg) = val;
}
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set)
{
u16 val = sdmmc_read16(reg);
val &= ~clear;
val |= set;
sdmmc_write16(reg, val);
}
static inline void setckl(u32 data)
{
sdmmc_mask16(REG_SDCLKCTL, 0x100, 0);
sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF);
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
}
mmcdevice *getMMCDevice(int drive) mmcdevice *getMMCDevice(int drive)
{ {
if(drive == 0) return &handleNAND; if(drive==0) return &handleNAND;
return &handleSD; return &handleSD;
} }
static int geterror(struct mmcdevice *ctx) static int get_error(struct mmcdevice *ctx)
{ {
return (int)((ctx->error << 29) >> 31); return (int)((ctx->error << 29) >> 31);
} }
static void inittarget(struct mmcdevice *ctx)
static void set_target(struct mmcdevice *ctx)
{ {
sdmmc_mask16(REG_SDPORTSEL, 0x3, (u16)ctx->devicenumber); sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber);
setckl(ctx->clk); setckl(ctx->clk);
if(ctx->SDOPT == 0) sdmmc_mask16(REG_SDOPT, 0, 0x8000); if(ctx->SDOPT == 0)
else sdmmc_mask16(REG_SDOPT, 0x8000, 0); {
sdmmc_mask16(REG_SDOPT,0,0x8000);
}
else
{
sdmmc_mask16(REG_SDOPT,0x8000,0);
}
} }
static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args) static void sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args)
{ {
u32 getSDRESP = (cmd << 15) >> 31; const bool getSDRESP = (cmd << 15) >> 31;
u16 flags = (cmd << 15) >> 31; u16 flags = (cmd << 15) >> 31;
const int readdata = cmd & 0x20000; const bool readdata = cmd & 0x20000;
const int writedata = cmd & 0x40000; const bool writedata = cmd & 0x40000;
if(readdata || writedata) if(readdata || writedata)
{
flags |= TMIO_STAT0_DATAEND; flags |= TMIO_STAT0_DATAEND;
}
ctx->error = 0; ctx->error = 0;
while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working? while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working?
sdmmc_write16(REG_SDIRMASK0, 0); sdmmc_write16(REG_SDIRMASK0,0);
sdmmc_write16(REG_SDIRMASK1, 0); sdmmc_write16(REG_SDIRMASK1,0);
sdmmc_write16(REG_SDSTATUS0, 0); sdmmc_write16(REG_SDSTATUS0,0);
sdmmc_write16(REG_SDSTATUS1, 0); sdmmc_write16(REG_SDSTATUS1,0);
sdmmc_mask16(REG_DATACTL32, 0x1800, 0); sdmmc_mask16(REG_DATACTL32,0x1800,0x400); // Disable TX32RQ and RX32RDY IRQ. Clear fifo.
sdmmc_write16(REG_SDCMDARG0, args & 0xFFFF); sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
sdmmc_write16(REG_SDCMDARG1, args >> 16); sdmmc_write16(REG_SDCMDARG1,args >> 16);
sdmmc_write16(REG_SDCMD, cmd & 0xFFFF); sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
u32 size = ctx->size; u32 size = ctx->size;
u8 *rDataPtr = ctx->rData; const u16 blkSize = sdmmc_read16(REG_SDBLKLEN32);
const u8 *tDataPtr = ctx->tData; u32 *rDataPtr32 = (u32*)(void*)ctx->rData;
u8 *rDataPtr8 = ctx->rData;
const u32 *tDataPtr32 = (u32*)(void*)ctx->tData;
const u8 *tDataPtr8 = ctx->tData;
bool rUseBuf = rDataPtr != NULL; bool rUseBuf = ( NULL != rDataPtr32 );
bool tUseBuf = tDataPtr != NULL; bool tUseBuf = ( NULL != tDataPtr32 );
u16 status0 = 0; u16 status0 = 0;
while(true) while(1)
{ {
vu16 status1 = sdmmc_read16(REG_SDSTATUS1); volatile u16 status1 = sdmmc_read16(REG_SDSTATUS1);
vu16 ctl32 = sdmmc_read16(REG_DATACTL32); #ifdef DATA32_SUPPORT
volatile u16 ctl32 = sdmmc_read16(REG_DATACTL32);
if((ctl32 & 0x100)) if((ctl32 & 0x100))
#else
if((status1 & TMIO_STAT1_RXRDY))
#endif
{ {
if(readdata) if(readdata)
{ {
if(rUseBuf) if(rUseBuf)
{ {
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
if(size > 0x1FF) if(size >= blkSize)
{ {
//Gabriel Marcano: This implementation doesn't assume alignment. #ifdef DATA32_SUPPORT
//I've removed the alignment check doen with former rUseBuf32 as a result if(!((u32)rDataPtr32 & 3))
for(int i = 0; i < 0x200; i += 4)
{ {
u32 data = sdmmc_read32(REG_SDFIFO32); for(u32 i = 0; i < blkSize; i += 4)
*rDataPtr++ = data; {
*rDataPtr++ = data >> 8; *rDataPtr32++ = sdmmc_read32(REG_SDFIFO32);
*rDataPtr++ = data >> 16; }
*rDataPtr++ = data >> 24;
} }
size -= 0x200; else
{
for(u32 i = 0; i < blkSize; i += 4)
{
u32 data = sdmmc_read32(REG_SDFIFO32);
*rDataPtr8++ = data;
*rDataPtr8++ = data >> 8;
*rDataPtr8++ = data >> 16;
*rDataPtr8++ = data >> 24;
}
}
#else
if(!((u32)rDataPtr16 & 1))
{
for(u32 i = 0; i < blkSize; i += 4)
{
*rDataPtr16++ = sdmmc_read16(REG_SDFIFO);
}
}
else
{
for(u32 i = 0; i < blkSize; i += 4)
{
u16 data = sdmmc_read16(REG_SDFIFO);
*rDataPtr8++ = data;
*rDataPtr8++ = data >> 8;
}
}
#endif
size -= blkSize;
} }
} }
sdmmc_mask16(REG_DATACTL32, 0x800, 0); sdmmc_mask16(REG_DATACTL32, 0x800, 0);
} }
} }
#ifdef DATA32_SUPPORT
if(!(ctl32 & 0x200)) if(!(ctl32 & 0x200))
#else
if((status1 & TMIO_STAT1_TXRQ))
#endif
{ {
if(writedata) if(writedata)
{ {
if(tUseBuf) if(tUseBuf)
{ {
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
if(size > 0x1FF) if(size >= blkSize)
{ {
for(int i = 0; i < 0x200; i += 4) #ifdef DATA32_SUPPORT
if(!((u32)tDataPtr32 & 3))
{ {
u32 data = *tDataPtr++; for(u32 i = 0; i < blkSize; i += 4)
data |= (u32)*tDataPtr++ << 8; {
data |= (u32)*tDataPtr++ << 16; sdmmc_write32(REG_SDFIFO32, *tDataPtr32++);
data |= (u32)*tDataPtr++ << 24; }
sdmmc_write32(REG_SDFIFO32, data);
} }
size -= 0x200; else
{
for(u32 i = 0; i < blkSize; i += 4)
{
u32 data = *tDataPtr8++;
data |= (u32)*tDataPtr8++ << 8;
data |= (u32)*tDataPtr8++ << 16;
data |= (u32)*tDataPtr8++ << 24;
sdmmc_write32(REG_SDFIFO32, data);
}
}
#else
if(!((u32)tDataPtr16 & 1))
{
for(u32 i = 0; i < blkSize; i += 2)
{
sdmmc_write16(REG_SDFIFO, *tDataPtr16++);
}
}
else
{
for(u32 i = 0; i < blkSize; i += 2)
{
u16 data = *tDataPtr8++;
data |= (u16)(*tDataPtr8++ << 8);
sdmmc_write16(REG_SDFIFO, data);
}
}
#endif
size -= blkSize;
} }
} }
@ -189,8 +235,8 @@ static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx,
} }
ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
sdmmc_write16(REG_SDSTATUS0, 0); sdmmc_write16(REG_SDSTATUS0,0);
sdmmc_write16(REG_SDSTATUS1, 0); sdmmc_write16(REG_SDSTATUS1,0);
if(getSDRESP != 0) if(getSDRESP != 0)
{ {
@ -201,213 +247,243 @@ static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx,
} }
} }
int __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in) int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in)
{ {
if(handleSD.isSDHC == 0) sector_no <<= 9; if(handleSD.isSDHC == 0) sector_no <<= 9;
inittarget(&handleSD); set_target(&handleSD);
sdmmc_write16(REG_SDSTOP, 0x100); sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT32, numsectors); #ifdef DATA32_SUPPORT
sdmmc_write16(REG_SDBLKLEN32, 0x200); sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKCOUNT, numsectors); sdmmc_write16(REG_SDBLKLEN32,0x200);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handleSD.tData = in; handleSD.tData = in;
handleSD.size = numsectors << 9; handleSD.size = numsectors << 9;
sdmmc_send_command(&handleSD, 0x52C19, sector_no); sdmmc_send_command(&handleSD,0x52C19,sector_no);
return geterror(&handleSD); return get_error(&handleSD);
} }
int __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out) int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out)
{ {
if(handleSD.isSDHC == 0) sector_no <<= 9; if(handleSD.isSDHC == 0) sector_no <<= 9;
inittarget(&handleSD); set_target(&handleSD);
sdmmc_write16(REG_SDSTOP, 0x100); sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT32, numsectors); #ifdef DATA32_SUPPORT
sdmmc_write16(REG_SDBLKLEN32, 0x200); sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKCOUNT, numsectors); sdmmc_write16(REG_SDBLKLEN32,0x200);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handleSD.rData = out; handleSD.rData = out;
handleSD.size = numsectors << 9; handleSD.size = numsectors << 9;
sdmmc_send_command(&handleSD, 0x33C12, sector_no); sdmmc_send_command(&handleSD,0x33C12,sector_no);
return geterror(&handleSD); return get_error(&handleSD);
} }
int __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out)
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out)
{ {
if(handleNAND.isSDHC == 0) sector_no <<= 9; if(handleNAND.isSDHC == 0) sector_no <<= 9;
inittarget(&handleNAND); set_target(&handleNAND);
sdmmc_write16(REG_SDSTOP, 0x100); sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT32, numsectors); #ifdef DATA32_SUPPORT
sdmmc_write16(REG_SDBLKLEN32, 0x200); sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKCOUNT, numsectors); sdmmc_write16(REG_SDBLKLEN32,0x200);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handleNAND.rData = out; handleNAND.rData = out;
handleNAND.size = numsectors << 9; handleNAND.size = numsectors << 9;
sdmmc_send_command(&handleNAND, 0x33C12, sector_no); sdmmc_send_command(&handleNAND,0x33C12,sector_no);
inittarget(&handleSD); return get_error(&handleNAND);
return geterror(&handleNAND);
} }
int __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in) //experimental int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in) //experimental
{ {
if(handleNAND.isSDHC == 0) sector_no <<= 9; if(handleNAND.isSDHC == 0) sector_no <<= 9;
inittarget(&handleNAND); set_target(&handleNAND);
sdmmc_write16(REG_SDSTOP, 0x100); sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT32, numsectors); #ifdef DATA32_SUPPORT
sdmmc_write16(REG_SDBLKLEN32, 0x200); sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKCOUNT, numsectors); sdmmc_write16(REG_SDBLKLEN32,0x200);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handleNAND.tData = in; handleNAND.tData = in;
handleNAND.size = numsectors << 9; handleNAND.size = numsectors << 9;
sdmmc_send_command(&handleNAND, 0x52C19, sector_no); sdmmc_send_command(&handleNAND,0x52C19,sector_no);
inittarget(&handleSD); return get_error(&handleNAND);
return geterror(&handleNAND);
} }
static u32 calcSDSize(u8 *csd, int type) static u32 sdmmc_calc_size(u8* csd, int type)
{ {
u32 result = 0; u32 result = 0;
if(type == -1) type = csd[14] >> 6; if(type == -1) type = csd[14] >> 6;
switch(type) switch(type)
{ {
case 0: case 0:
{ {
u32 block_len = csd[9] & 0xF; u32 block_len=csd[9]&0xf;
block_len = 1u << block_len; block_len=1u<<block_len;
u32 mult = (u32)((csd[4] >> 7) | ((csd[5] & 3) << 1)); u32 mult=( u32)((csd[4]>>7)|((csd[5]&3)<<1));
mult = 1u << (mult + 2); mult=1u<<(mult+2);
result = csd[8] & 3; result=csd[8]&3;
result = (result << 8) | csd[7]; result=(result<<8)|csd[7];
result = (result << 2) | (csd[6] >> 6); result=(result<<2)|(csd[6]>>6);
result = (result + 1) * mult * block_len / 512; result=(result+1)*mult*block_len/512;
break; }
} break;
case 1: case 1:
result = csd[7] & 0x3F; result=csd[7]&0x3f;
result = (result << 8) | csd[6]; result=(result<<8)|csd[6];
result = (result << 8) | csd[5]; result=(result<<8)|csd[5];
result = (result + 1) * 1024; result=(result+1)*1024;
break; break;
default: default:
break; //Do nothing otherwise FIXME perhaps return some error? break; //Do nothing otherwise FIXME perhaps return some error?
} }
return result; return result;
} }
static void InitSD() void sdmmc_init()
{
*(vu32 *)0x10000020 = 0; //InitFS stuff
*(vu32 *)0x10000020 = 0x200; //InitFS stuff
*(vu16 *)0x10006100 &= 0xF7FFu; //SDDATACTL32
*(vu16 *)0x10006100 &= 0xEFFFu; //SDDATACTL32
*(vu16 *)0x10006100 |= 0x402u; //SDDATACTL32
*(vu16 *)0x100060D8 = (*(vu16 *)0x100060D8 & 0xFFDD) | 2;
*(vu16 *)0x10006100 &= 0xFFFFu; //SDDATACTL32
*(vu16 *)0x100060D8 &= 0xFFDFu; //SDDATACTL
*(vu16 *)0x10006104 = 512; //SDBLKLEN32
*(vu16 *)0x10006108 = 1; //SDBLKCOUNT32
*(vu16 *)0x100060E0 &= 0xFFFEu; //SDRESET
*(vu16 *)0x100060E0 |= 1u; //SDRESET
*(vu16 *)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
*(vu16 *)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
*(vu16 *)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
*(vu16 *)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
*(vu16 *)0x10006002 &= 0xFFFCu; //SDPORTSEL
*(vu16 *)0x10006024 = 0x20;
*(vu16 *)0x10006028 = 0x40EE;
*(vu16 *)0x10006002 &= 0xFFFCu; ////SDPORTSEL
*(vu16 *)0x10006026 = 512; //SDBLKLEN
*(vu16 *)0x10006008 = 0; //SDSTOP
}
static int Nand_Init()
{ {
//NAND //NAND
handleNAND.isSDHC = 0; handleNAND.isSDHC = 0;
handleNAND.SDOPT = 0; handleNAND.SDOPT = 0;
handleNAND.res = 0; handleNAND.res = 0;
handleNAND.initarg = 1; handleNAND.initarg = 1;
handleNAND.clk = 0x80; handleNAND.clk = 0x20; // 523.655968 KHz
handleNAND.devicenumber = 1; handleNAND.devicenumber = 1;
inittarget(&handleNAND);
waitcycles(0xF000);
sdmmc_send_command(&handleNAND, 0, 0);
do
{
do
{
sdmmc_send_command(&handleNAND, 0x10701, 0x100000);
}
while(!(handleNAND.error & 1));
}
while((handleNAND.ret[0] & 0x80000000) == 0);
sdmmc_send_command(&handleNAND, 0x10602, 0x0);
if((handleNAND.error & 0x4)) return -1;
sdmmc_send_command(&handleNAND, 0x10403, handleNAND.initarg << 0x10);
if((handleNAND.error & 0x4)) return -1;
sdmmc_send_command(&handleNAND, 0x10609, handleNAND.initarg << 0x10);
if((handleNAND.error & 0x4)) return -1;
handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0], 0);
handleNAND.clk = 1;
setckl(1);
sdmmc_send_command(&handleNAND, 0x10407, handleNAND.initarg << 0x10);
if((handleNAND.error & 0x4)) return -1;
handleNAND.SDOPT = 1;
sdmmc_send_command(&handleNAND, 0x10506, 0x3B70100);
if((handleNAND.error & 0x4)) return -1;
sdmmc_send_command(&handleNAND, 0x10506, 0x3B90100);
if((handleNAND.error & 0x4)) return -1;
sdmmc_send_command(&handleNAND, 0x1040D, handleNAND.initarg << 0x10);
if((handleNAND.error & 0x4)) return -1;
sdmmc_send_command(&handleNAND, 0x10410, 0x200);
if((handleNAND.error & 0x4)) return -1;
handleNAND.clk |= 0x200;
inittarget(&handleSD);
return 0;
}
static int SD_Init()
{
//SD //SD
handleSD.isSDHC = 0; handleSD.isSDHC = 0;
handleSD.SDOPT = 0; handleSD.SDOPT = 0;
handleSD.res = 0; handleSD.res = 0;
handleSD.initarg = 0; handleSD.initarg = 0;
handleSD.clk = 0x80; handleSD.clk = 0x20; // 523.655968 KHz
handleSD.devicenumber = 0; handleSD.devicenumber = 0;
inittarget(&handleSD); *(vu16*)0x10006100 &= 0xF7FFu; //SDDATACTL32
*(vu16*)0x10006100 &= 0xEFFFu; //SDDATACTL32
#ifdef DATA32_SUPPORT
*(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
#else
*(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
#endif
*(vu16*)0x100060D8 = (*(vu16*)0x100060D8 & 0xFFDD) | 2;
#ifdef DATA32_SUPPORT
*(vu16*)0x10006100 &= 0xFFFFu; //SDDATACTL32
*(vu16*)0x100060D8 &= 0xFFDFu; //SDDATACTL
*(vu16*)0x10006104 = 512; //SDBLKLEN32
#else
*(vu16*)0x10006100 &= 0xFFFDu; //SDDATACTL32
*(vu16*)0x100060D8 &= 0xFFDDu; //SDDATACTL
*(vu16*)0x10006104 = 0; //SDBLKLEN32
#endif
*(vu16*)0x10006108 = 1; //SDBLKCOUNT32
*(vu16*)0x100060E0 &= 0xFFFEu; //SDRESET
*(vu16*)0x100060E0 |= 1u; //SDRESET
*(vu16*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
*(vu16*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
*(vu16*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
*(vu16*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
*(vu16*)0x10006002 &= 0xFFFCu; //SDPORTSEL
#ifdef DATA32_SUPPORT
*(vu16*)0x10006024 = 0x20;
*(vu16*)0x10006028 = 0x40E9;
#else
*(vu16*)0x10006024 = 0x40; //Nintendo sets this to 0x20
*(vu16*)0x10006028 = 0x40E9; //Nintendo sets this to 0x40EE
#endif
*(vu16*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
*(vu16*)0x10006026 = 512; //SDBLKLEN
*(vu16*)0x10006008 = 0; //SDSTOP
}
waitcycles(1u << 22); //Card needs a little bit of time to be detected, it seems FIXME test again to see what a good number is for the delay int Nand_Init()
{
// init the handle
handleNAND.isSDHC = 0;
handleNAND.SDOPT = 0;
handleNAND.res = 0;
handleNAND.initarg = 1;
handleNAND.clk = 0x20; // 523.655968 KHz
handleNAND.devicenumber = 1;
//If not inserted // The eMMC is always on. Nothing special to do.
if(!(*((vu16 *)(SDMMC_BASE + REG_SDSTATUS0)) & TMIO_STAT0_SIGSTATE)) return 5; set_target(&handleNAND);
sdmmc_send_command(&handleSD, 0, 0); sdmmc_send_command(&handleNAND,0,0);
sdmmc_send_command(&handleSD, 0x10408, 0x1AA);
u32 temp = (handleSD.error & 0x1) << 0x1E;
u32 temp2 = 0;
do do
{ {
do do
{ {
sdmmc_send_command(&handleSD, 0x10437, handleSD.initarg << 0x10); sdmmc_send_command(&handleNAND,0x10701,0x100000);
sdmmc_send_command(&handleSD, 0x10769, 0x00FF8000 | temp); } while ( !(handleNAND.error & 1) );
}
while((handleNAND.ret[0] & 0x80000000) == 0);
sdmmc_send_command(&handleNAND,0x10602,0x0);
if((handleNAND.error & 0x4))return -1;
sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10);
if((handleNAND.error & 0x4))return -1;
sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10);
if((handleNAND.error & 0x4))return -1;
handleNAND.total_size = sdmmc_calc_size((u8*)&handleNAND.ret[0],0);
setckl(0x201); // 16.756991 MHz
sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10);
if((handleNAND.error & 0x4))return -1;
handleNAND.SDOPT = 1;
sdmmc_send_command(&handleNAND,0x10506,0x3B70100); // Set 4 bit bus width.
if((handleNAND.error & 0x4))return -1;
sdmmc_mask16(REG_SDOPT, 0x8000, 0); // Switch to 4 bit mode.
sdmmc_send_command(&handleNAND,0x10506,0x3B90100); // Switch to high speed timing.
if((handleNAND.error & 0x4))return -1;
handleNAND.clk = 0x200; // 33.513982 MHz
setckl(0x200);
sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10);
if((handleNAND.error & 0x4))return -1;
sdmmc_send_command(&handleNAND,0x10410,0x200);
if((handleNAND.error & 0x4))return -1;
return 0;
}
int SD_Init()
{
// init the handle
handleSD.isSDHC = 0;
handleSD.SDOPT = 0;
handleSD.res = 0;
handleSD.initarg = 0;
handleSD.clk = 0x20; // 523.655968 KHz
handleSD.devicenumber = 0;
// We need to send at least 74 clock pulses.
set_target(&handleSD);
wait_cycles(0x1980); // ~75-76 clocks
sdmmc_send_command(&handleSD,0,0);
sdmmc_send_command(&handleSD,0x10408,0x1AA);
u32 temp = (handleSD.error & 0x1) << 0x1E;
u32 temp2 = 0;
do
{
do
{
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
sdmmc_send_command(&handleSD,0x10769,0x10100000 | temp); // Allow 150mA, 3.2-3.3V (from Process9)
temp2 = 1; temp2 = 1;
} } while ( !(handleSD.error & 1) );
while(!(handleSD.error & 1));
} }
while((handleSD.ret[0] & 0x80000000) == 0); while((handleSD.ret[0] & 0x80000000) == 0);
@ -416,67 +492,127 @@ static int SD_Init()
handleSD.isSDHC = temp2; handleSD.isSDHC = temp2;
sdmmc_send_command(&handleSD, 0x10602, 0); sdmmc_send_command(&handleSD,0x10602,0);
if((handleSD.error & 0x4)) return -1; if((handleSD.error & 0x4)) return -1;
sdmmc_send_command(&handleSD, 0x10403, 0); sdmmc_send_command(&handleSD,0x10403,0);
if((handleSD.error & 0x4)) return -2; if((handleSD.error & 0x4)) return -2;
handleSD.initarg = handleSD.ret[0] >> 0x10; handleSD.initarg = handleSD.ret[0] >> 0x10;
sdmmc_send_command(&handleSD, 0x10609, handleSD.initarg << 0x10); sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10);
if((handleSD.error & 0x4)) return -3; if((handleSD.error & 0x4)) return -3;
handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0], -1); // Command Class 10 support
handleSD.clk = 1; const bool cmd6Supported = ((u8*)handleSD.ret)[10] & 0x40;
setckl(1); handleSD.total_size = sdmmc_calc_size((u8*)&handleSD.ret[0],-1);
setckl(0x201); // 16.756991 MHz
sdmmc_send_command(&handleSD, 0x10507, handleSD.initarg << 0x10); sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10);
if((handleSD.error & 0x4)) return -4; if((handleSD.error & 0x4)) return -4;
sdmmc_send_command(&handleSD, 0x10437, handleSD.initarg << 0x10); // CMD55
if((handleSD.error & 0x4)) return -5; sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
if(handleSD.error & 0x4) return -5;
handleSD.SDOPT = 1; // ACMD42 SET_CLR_CARD_DETECT
sdmmc_send_command(&handleSD, 0x10446, 0x2); sdmmc_send_command(&handleSD,0x1076A,0x0);
if((handleSD.error & 0x4)) return -6; if(handleSD.error & 0x4) return -6;
sdmmc_send_command(&handleSD, 0x1040D, handleSD.initarg << 0x10); sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
if((handleSD.error & 0x4)) return -7; if((handleSD.error & 0x4)) return -7;
sdmmc_send_command(&handleSD, 0x10410, 0x200); handleSD.SDOPT = 1;
sdmmc_send_command(&handleSD,0x10446,0x2);
if((handleSD.error & 0x4)) return -8; if((handleSD.error & 0x4)) return -8;
handleSD.clk |= 0x200; sdmmc_mask16(REG_SDOPT, 0x8000, 0); // Switch to 4 bit mode.
// TODO: CMD6 to switch to high speed mode.
if(cmd6Supported)
{
sdmmc_write16(REG_SDSTOP,0);
sdmmc_write16(REG_SDBLKLEN32,64);
sdmmc_write16(REG_SDBLKLEN,64);
handleSD.rData = NULL;
handleSD.size = 64;
sdmmc_send_command(&handleSD,0x31C06,0x80FFFFF1);
sdmmc_write16(REG_SDBLKLEN,512);
if(handleSD.error & 0x4) return -9;
handleSD.clk = 0x200; // 33.513982 MHz
setckl(0x200);
}
else handleSD.clk = 0x201; // 16.756991 MHz
sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10);
if((handleSD.error & 0x4)) return -9;
sdmmc_send_command(&handleSD,0x10410,0x200);
if((handleSD.error & 0x4)) return -10;
return 0; return 0;
} }
void sdmmc_get_cid(bool isNand, u32 *info) int sdmmc_get_cid(bool isNand, u32 *info)
{ {
struct mmcdevice *device = isNand ? &handleNAND : &handleSD; struct mmcdevice *device;
if(isNand)
inittarget(device); device = &handleNAND;
else
device = &handleSD;
set_target(device);
// use cmd7 to put sd card in standby mode // use cmd7 to put sd card in standby mode
// CMD7 // CMD7
sdmmc_send_command(device, 0x10507, 0); {
sdmmc_send_command(device,0x10507,0);
//if((device->error & 0x4)) return -1;
}
// get sd card info // get sd card info
// use cmd10 to read CID // use cmd10 to read CID
sdmmc_send_command(device, 0x1060A, device->initarg << 0x10); {
sdmmc_send_command(device,0x1060A,device->initarg << 0x10);
//if((device->error & 0x4)) return -2;
for(int i = 0; i < 4; ++i) for( int i = 0; i < 4; ++i ) {
info[i] = device->ret[i]; info[i] = device->ret[i];
}
}
// put sd card back to transfer mode // put sd card back to transfer mode
// CMD7 // CMD7
sdmmc_send_command(device, 0x10507, device->initarg << 0x10); {
sdmmc_send_command(device,0x10507,device->initarg << 0x10);
//if((device->error & 0x4)) return -3;
}
return 0;
} }
u32 sdmmc_sdcard_init() u32 sdmmc_sdcard_init()
{ {
u32 ret = 0; u32 ret = 0;
InitSD();
// SD mount fix
*((vu16*)0x10000020) = 0x340;
// init SDMMC / NAND
sdmmc_init();
if(Nand_Init() != 0) ret &= 1; if(Nand_Init() != 0) ret &= 1;
if(SD_Init() != 0) ret &= 2;
// init SDMMC / SDCARD
u32 timeout = 20; // number of tries (2ms per try)
do {
// if sd card is ready, stop polling
if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_SIGSTATE)
break;
wait_cycles(268000000); // approx 2ms
timeout--;
} while(timeout);
if(!timeout || SD_Init() != 0) ret &= 2;
return ret; return ret;
} }

View File

@ -1,100 +1,182 @@
#pragma once #pragma once
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2014-2015, Normmatt
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License Version 2, as described below:
*
* This file is free software: you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
#include "../../types.h" #include "../../types.h"
#define SDMMC_BASE 0x10006000 #define SDMMC_BASE (0x10006000)
#define REG_SDCMD 0x00 #define REG_SDCMD (0x00)
#define REG_SDPORTSEL 0x02 #define REG_SDPORTSEL (0x02)
#define REG_SDCMDARG 0x04 #define REG_SDCMDARG (0x04)
#define REG_SDCMDARG0 0x04 #define REG_SDCMDARG0 (0x04)
#define REG_SDCMDARG1 0x06 #define REG_SDCMDARG1 (0x06)
#define REG_SDSTOP 0x08 #define REG_SDSTOP (0x08)
#define REG_SDBLKCOUNT 0x0A #define REG_SDBLKCOUNT (0x0a)
#define REG_SDRESP0 0x0C #define REG_SDRESP0 (0x0c)
#define REG_SDRESP1 0x0E #define REG_SDRESP1 (0x0e)
#define REG_SDRESP2 0x10 #define REG_SDRESP2 (0x10)
#define REG_SDRESP3 0x12 #define REG_SDRESP3 (0x12)
#define REG_SDRESP4 0x14 #define REG_SDRESP4 (0x14)
#define REG_SDRESP5 0x16 #define REG_SDRESP5 (0x16)
#define REG_SDRESP6 0x18 #define REG_SDRESP6 (0x18)
#define REG_SDRESP7 0x1A #define REG_SDRESP7 (0x1a)
#define REG_SDSTATUS0 0x1C #define REG_SDSTATUS0 (0x1c)
#define REG_SDSTATUS1 0x1E #define REG_SDSTATUS1 (0x1e)
#define REG_SDIRMASK0 0x20 #define REG_SDIRMASK0 (0x20)
#define REG_SDIRMASK1 0x22 #define REG_SDIRMASK1 (0x22)
#define REG_SDCLKCTL 0x24 #define REG_SDCLKCTL (0x24)
#define REG_SDBLKLEN 0x26 #define REG_SDBLKLEN (0x26)
#define REG_SDOPT 0x28 #define REG_SDOPT (0x28)
#define REG_SDFIFO 0x30 #define REG_SDFIFO (0x30)
#define REG_DATACTL 0xD8 #define REG_DATACTL (0xd8)
#define REG_SDRESET 0xE0 #define REG_SDRESET (0xe0)
#define REG_SDPROTECTED 0xF6 //bit 0 determines if sd is protected or not? #define REG_SDPROTECTED (0xf6) //bit 0 determines if sd is protected or not?
#define REG_DATACTL32 0x100 #define REG_DATACTL32 (0x100)
#define REG_SDBLKLEN32 0x104 #define REG_SDBLKLEN32 (0x104)
#define REG_SDBLKCOUNT32 0x108 #define REG_SDBLKCOUNT32 (0x108)
#define REG_SDFIFO32 0x10C #define REG_SDFIFO32 (0x10C)
#define REG_CLK_AND_WAIT_CTL 0x138 #define REG_CLK_AND_WAIT_CTL (0x138)
#define REG_RESET_SDIO 0x1E0 #define REG_RESET_SDIO (0x1e0)
#define TMIO_STAT0_CMDRESPEND 0x0001 #define TMIO_STAT0_CMDRESPEND (0x0001)
#define TMIO_STAT0_DATAEND 0x0004 #define TMIO_STAT0_DATAEND (0x0004)
#define TMIO_STAT0_CARD_REMOVE 0x0008 #define TMIO_STAT0_CARD_REMOVE (0x0008)
#define TMIO_STAT0_CARD_INSERT 0x0010 #define TMIO_STAT0_CARD_INSERT (0x0010)
#define TMIO_STAT0_SIGSTATE 0x0020 #define TMIO_STAT0_SIGSTATE (0x0020)
#define TMIO_STAT0_WRPROTECT 0x0080 #define TMIO_STAT0_WRPROTECT (0x0080)
#define TMIO_STAT0_CARD_REMOVE_A 0x0100 #define TMIO_STAT0_CARD_REMOVE_A (0x0100)
#define TMIO_STAT0_CARD_INSERT_A 0x0200 #define TMIO_STAT0_CARD_INSERT_A (0x0200)
#define TMIO_STAT0_SIGSTATE_A 0x0400 #define TMIO_STAT0_SIGSTATE_A (0x0400)
#define TMIO_STAT1_CMD_IDX_ERR 0x0001 #define TMIO_STAT1_CMD_IDX_ERR (0x0001)
#define TMIO_STAT1_CRCFAIL 0x0002 #define TMIO_STAT1_CRCFAIL (0x0002)
#define TMIO_STAT1_STOPBIT_ERR 0x0004 #define TMIO_STAT1_STOPBIT_ERR (0x0004)
#define TMIO_STAT1_DATATIMEOUT 0x0008 #define TMIO_STAT1_DATATIMEOUT (0x0008)
#define TMIO_STAT1_RXOVERFLOW 0x0010 #define TMIO_STAT1_RXOVERFLOW (0x0010)
#define TMIO_STAT1_TXUNDERRUN 0x0020 #define TMIO_STAT1_TXUNDERRUN (0x0020)
#define TMIO_STAT1_CMDTIMEOUT 0x0040 #define TMIO_STAT1_CMDTIMEOUT (0x0040)
#define TMIO_STAT1_RXRDY 0x0100 #define TMIO_STAT1_RXRDY (0x0100)
#define TMIO_STAT1_TXRQ 0x0200 #define TMIO_STAT1_TXRQ (0x0200)
#define TMIO_STAT1_ILL_FUNC 0x2000 #define TMIO_STAT1_ILL_FUNC (0x2000)
#define TMIO_STAT1_CMD_BUSY 0x4000 #define TMIO_STAT1_CMD_BUSY (0x4000)
#define TMIO_STAT1_ILL_ACCESS 0x8000 #define TMIO_STAT1_ILL_ACCESS (0x8000)
#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 | \ #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) 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) #define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
typedef struct mmcdevice { #define SD_WRITE_PROTECTED (((*((vu16*)(SDMMC_BASE + REG_SDSTATUS0))) & (1 << 7 | 1 << 5)) == (1 << 5))
u8 *rData;
const u8 *tData;
u32 size;
u32 error;
u16 stat0;
u16 stat1;
u32 ret[4];
u32 initarg;
u32 isSDHC;
u32 clk;
u32 SDOPT;
u32 devicenumber;
u32 total_size; //size in sectors of the device
u32 res;
} mmcdevice;
u32 sdmmc_sdcard_init(); #ifdef __cplusplus
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out); extern "C" {
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in); #endif
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in); typedef struct mmcdevice {
void sdmmc_get_cid(bool isNand, u32 *info); u8* rData;
mmcdevice *getMMCDevice(int drive); const u8* tData;
u32 size;
u32 error;
u16 stat0;
u16 stat1;
u32 ret[4];
u32 initarg;
u32 isSDHC;
u32 clk;
u32 SDOPT;
u32 devicenumber;
u32 total_size; //size in sectors of the device
u32 res;
} mmcdevice;
void sdmmc_init();
int sdmmc_sdcard_readsector(u32 sector_no, u8 *out);
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
int sdmmc_sdcard_writesector(u32 sector_no, const u8 *in);
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
int sdmmc_get_cid(bool isNand, u32 *info);
mmcdevice *getMMCDevice(int drive);
int Nand_Init();
int SD_Init();
u32 sdmmc_sdcard_init();
#ifdef __cplusplus
};
#endif
//---------------------------------------------------------------------------------
static inline u16 sdmmc_read16(u16 reg) {
//---------------------------------------------------------------------------------
return *(volatile u16*)(SDMMC_BASE + reg);
}
//---------------------------------------------------------------------------------
static inline void sdmmc_write16(u16 reg, u16 val) {
//---------------------------------------------------------------------------------
*(volatile u16*)(SDMMC_BASE + reg) = val;
}
//---------------------------------------------------------------------------------
static inline u32 sdmmc_read32(u16 reg) {
//---------------------------------------------------------------------------------
return *(volatile u32*)(SDMMC_BASE + reg);
}
//---------------------------------------------------------------------------------
static inline void sdmmc_write32(u16 reg, u32 val) {
//---------------------------------------------------------------------------------
*(volatile u32*)(SDMMC_BASE + reg) = val;
}
//---------------------------------------------------------------------------------
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) {
//---------------------------------------------------------------------------------
u16 val = sdmmc_read16(reg);
val &= ~clear;
val |= set;
sdmmc_write16(reg, val);
}
static inline void setckl(u32 data)
{
sdmmc_write16(REG_SDCLKCTL, data & 0xFF);
sdmmc_write16(REG_SDCLKCTL, 1u<<8 | (data & 0x2FF));
}

View File

@ -2,4 +2,4 @@
#include "../../types.h" #include "../../types.h"
void waitcycles(u32 us); void wait_cycles(u32 us);

View File

@ -0,0 +1,11 @@
.arm
.section .text.wait_cycles, "ax", %progbits
.align 2
.global wait_cycles
.type wait_cycles, %function
wait_cycles:
subs r0, #2
nop
bgt wait_cycles
bx lr