Lightweight SD card FAT file system. Originaled by chan http://elm-chan.org/fsw/ff/00index_p.html

Petit FAT File System for LPC1114

originaled by elm

If you want to use except LPC1114, you can change pin definitions at mmcPinConfig.h

more detail and original code at http://elm-chan.org/fsw/ff/00index_p.html

This library is NOT compatible with mbed official SDFileSystem

Files at this revision

API Documentation at this revision

Comitter:
hsgw
Date:
Fri May 09 19:41:49 2014 +0000
Commit message:
1st commit

Changed in this revision

diskio.h Show annotated file Show diff for this revision Revisions of this file
integer.h Show annotated file Show diff for this revision Revisions of this file
mmc.cpp Show annotated file Show diff for this revision Revisions of this file
mmcPinConfig.h Show annotated file Show diff for this revision Revisions of this file
pff.cpp Show annotated file Show diff for this revision Revisions of this file
pff.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 845390b117a7 diskio.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/diskio.h	Fri May 09 19:41:49 2014 +0000
@@ -0,0 +1,41 @@
+/*-----------------------------------------------------------------------
+/  PFF - Low level disk interface modlue include file    (C)ChaN, 2009
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO
+
+#include "integer.h"
+
+
+/* Status of Disk Functions */
+typedef BYTE	DSTATUS;
+
+
+/* Results of Disk Functions */
+typedef enum {
+	RES_OK = 0,		/* 0: Function succeeded */
+	RES_ERROR,		/* 1: Disk error */
+	RES_NOTRDY,		/* 2: Not ready */
+	RES_PARERR		/* 3: Invalid parameter */
+} DRESULT;
+
+
+/*---------------------------------------*/
+/* Prototypes for disk control functions */
+
+DSTATUS disk_initialize (void);
+DRESULT disk_readp (BYTE*, DWORD, WORD, WORD);
+DRESULT disk_writep (const BYTE*, DWORD);
+
+#define STA_NOINIT		0x01	/* Drive not initialized */
+#define STA_NODISK		0x02	/* No medium in the drive */
+
+/* Card type flags (CardType) */
+#define CT_MMC				0x01	/* MMC ver 3 */
+#define CT_SD1				0x02	/* SD ver 1 */
+#define CT_SD2				0x04	/* SD ver 2 */
+#define CT_SDC				(CT_SD1|CT_SD2)	/* SD */
+#define CT_BLOCK			0x08	/* Block addressing */
+
+#define _DISKIO
+#endif
diff -r 000000000000 -r 845390b117a7 integer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/integer.h	Fri May 09 19:41:49 2014 +0000
@@ -0,0 +1,37 @@
+/*-------------------------------------------*/
+/* Integer type definitions for FatFs module */
+/*-------------------------------------------*/
+
+#ifndef _INTEGER
+#define _INTEGER
+
+#ifdef _WIN32	/* FatFs development platform */
+
+#include <windows.h>
+#include <tchar.h>
+
+#else			/* Embedded platform */
+
+/* These types must be 16-bit, 32-bit or larger integer */
+typedef int				INT;
+typedef unsigned int	UINT;
+
+/* These types must be 8-bit integer */
+typedef char			CHAR;
+typedef unsigned char	UCHAR;
+typedef unsigned char	BYTE;
+
+/* These types must be 16-bit integer */
+typedef short			SHORT;
+typedef unsigned short	USHORT;
+typedef unsigned short	WORD;
+typedef unsigned short	WCHAR;
+
+/* These types must be 32-bit integer */
+typedef long			LONG;
+typedef unsigned long	ULONG;
+typedef unsigned long	DWORD;
+
+#endif
+
+#endif
diff -r 000000000000 -r 845390b117a7 mmc.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmc.cpp	Fri May 09 19:41:49 2014 +0000
@@ -0,0 +1,289 @@
+/*-------------------------------------------------------------------------*/
+/*PFF for mbed porting by Takuya Urakawa*/
+/*Based on PFF - Low level disk control module for PIC            (C)ChaN, 2010    */
+/*-------------------------------------------------------------------------*/
+
+#include "pff.h"
+#include "diskio.h"
+
+/*-------------------------------------------------------------------------*/
+/* Platform dependent macros and functions needed to be modified           */
+/*-------------------------------------------------------------------------*/
+
+#include "mbed.h"
+#include "mmcPinConfig.h"
+
+#define SELECT()	cs.write(0)		/* CS = L */
+#define	DESELECT()	cs.write(1)		/* CS = H */
+#define	MMC_SEL		!cs.read()		/* CS status (true:CS == L) */
+#define	FORWARD(d)	putchar(d)		/* Data forwarding function (Console out in this example) */
+
+#define SPI_SPEED (20000000)
+
+SPI spi(MMC_MOSI, MMC_MISO, MMC_SCLK);
+DigitalOut cs(MMC_CS);
+
+
+static
+void init_spi (void)		/* Initialize SPI port */
+{
+	cs = 1;
+	spi.format(8);
+  spi.frequency(100000);
+}
+
+void dly_100us (void)		/* Delay 100 microseconds */
+{
+	wait_us(100);
+}
+
+static
+void xmit_spi (BYTE d)		/* Send a byte to the MMC */
+{
+	spi.write(d);
+}
+
+static
+BYTE rcv_spi (void)			/* Send a 0xFF to the MMC and get the received byte */
+{
+	return spi.write(0xFF);
+}
+
+/*--------------------------------------------------------------------------
+
+   Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+/* Definitions for MMC/SDC command */
+#define CMD0	(0x40+0)	/* GO_IDLE_STATE */
+#define CMD1	(0x40+1)	/* SEND_OP_COND (MMC) */
+#define	ACMD41	(0xC0+41)	/* SEND_OP_COND (SDC) */
+#define CMD8	(0x40+8)	/* SEND_IF_COND */
+#define CMD16	(0x40+16)	/* SET_BLOCKLEN */
+#define CMD17	(0x40+17)	/* READ_SINGLE_BLOCK */
+#define CMD24	(0x40+24)	/* WRITE_BLOCK */
+#define CMD55	(0x40+55)	/* APP_CMD */
+#define CMD58	(0x40+58)	/* READ_OCR */
+
+
+/* Card type flags (CardType) */
+#define CT_MMC				0x01	/* MMC ver 3 */
+#define CT_SD1				0x02	/* SD ver 1 */
+#define CT_SD2				0x04	/* SD ver 2 */
+#define CT_BLOCK			0x08	/* Block addressing */
+
+
+static
+BYTE CardType;
+
+
+/*-----------------------------------------------------------------------*/
+/* Send a command packet to MMC                                          */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE send_cmd (
+	BYTE cmd,		/* 1st byte (Start + Index) */
+	DWORD arg		/* Argument (32 bits) */
+)
+{
+	BYTE n, res;
+
+
+	if (cmd & 0x80) {	/* ACMD<n> is the command sequense of CMD55-CMD<n> */
+		cmd &= 0x7F;
+		res = send_cmd(CMD55, 0);
+		if (res > 1) return res;
+	}
+
+	/* Select the card */
+	DESELECT();
+	rcv_spi();
+	SELECT();
+	rcv_spi();
+
+	/* Send a command packet */
+	xmit_spi(cmd);						/* Start + Command index */
+	xmit_spi((BYTE)(arg >> 24));		/* Argument[31..24] */
+	xmit_spi((BYTE)(arg >> 16));		/* Argument[23..16] */
+	xmit_spi((BYTE)(arg >> 8));			/* Argument[15..8] */
+	xmit_spi((BYTE)arg);				/* Argument[7..0] */
+	n = 0x01;							/* Dummy CRC + Stop */
+	if (cmd == CMD0) n = 0x95;			/* Valid CRC for CMD0(0) */
+	if (cmd == CMD8) n = 0x87;			/* Valid CRC for CMD8(0x1AA) */
+	xmit_spi(n);
+
+	/* Receive a command response */
+	n = 10;								/* Wait for a valid response in timeout of 10 attempts */
+	do {
+		res = rcv_spi();
+	} while ((res & 0x80) && --n);
+
+	return res;			/* Return with the response value */
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Public Functions
+
+---------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------*/
+/* Initialize Disk Drive                                                 */
+/*-----------------------------------------------------------------------*/
+
+DSTATUS disk_initialize (void)
+{
+	BYTE n, cmd, ty, ocr[4];
+	UINT tmr;
+
+#if _USE_WRITE
+	if (CardType && MMC_SEL) disk_writep(0, 0);	/* Finalize write process if it is in progress */
+#endif
+	init_spi();		/* Initialize ports to control MMC */
+	DESELECT();
+	for (n = 10; n; n--) rcv_spi();	/* 80 Dummy clocks with CS=H */
+
+	ty = 0;
+	if (send_cmd(CMD0, 0) == 1) {			/* Enter Idle state */
+		if (send_cmd(CMD8, 0x1AA) == 1) {	/* SDv2 */
+			for (n = 0; n < 4; n++) ocr[n] = rcv_spi();		/* Get trailing return value of R7 resp */
+			if (ocr[2] == 0x01 && ocr[3] == 0xAA) {			/* The card can work at vdd range of 2.7-3.6V */
+				for (tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) dly_100us();	/* Wait for leaving idle state (ACMD41 with HCS bit) */
+				if (tmr && send_cmd(CMD58, 0) == 0) {		/* Check CCS bit in the OCR */
+					for (n = 0; n < 4; n++) ocr[n] = rcv_spi();
+					ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;	/* SDv2 (HC or SC) */
+				}
+			}
+		} else {							/* SDv1 or MMCv3 */
+			if (send_cmd(ACMD41, 0) <= 1) 	{
+				ty = CT_SD1; cmd = ACMD41;	/* SDv1 */
+			} else {
+				ty = CT_MMC; cmd = CMD1;	/* MMCv3 */
+			}
+			for (tmr = 10000; tmr && send_cmd(cmd, 0); tmr--) dly_100us();	/* Wait for leaving idle state */
+			if (!tmr || send_cmd(CMD16, 512) != 0)			/* Set R/W block length to 512 */
+				ty = 0;
+		}
+	}
+	CardType = ty;
+	DESELECT();
+	rcv_spi();
+	
+	spi.frequency(SPI_SPEED);
+
+	return ty ? 0 : STA_NOINIT;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read partial sector                                                   */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_readp (
+	BYTE *buff,		/* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
+	DWORD lba,		/* Sector number (LBA) */
+	WORD ofs,		/* Byte offset to read from (0..511) */
+	WORD cnt		/* Number of bytes to read (ofs + cnt mus be <= 512) */
+)
+{
+	DRESULT res;
+	BYTE rc;
+	WORD bc;
+
+
+	if (!(CardType & CT_BLOCK)) lba *= 512;		/* Convert to byte address if needed */
+
+	res = RES_ERROR;
+	if (send_cmd(CMD17, lba) == 0) {		/* READ_SINGLE_BLOCK */
+
+		bc = 40000;
+		do {							/* Wait for data packet */
+			rc = rcv_spi();
+		} while (rc == 0xFF && --bc);
+
+		if (rc == 0xFE) {				/* A data packet arrived */
+			bc = 514 - ofs - cnt;
+
+			/* Skip leading bytes */
+			if (ofs) {
+				do rcv_spi(); while (--ofs);
+			}
+
+			/* Receive a part of the sector */
+			if (buff) {	/* Store data to the memory */
+				do {
+					*buff++ = rcv_spi();
+				} while (--cnt);
+			} else {	/* Forward data to the outgoing stream (depends on the project) */
+				do {
+					FORWARD(rcv_spi());
+				} while (--cnt);
+			}
+
+			/* Skip trailing bytes and CRC */
+			do rcv_spi(); while (--bc);
+
+			res = RES_OK;
+		}
+	}
+
+	DESELECT();
+	rcv_spi();
+
+	return res;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write partial sector                                                  */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_WRITE
+DRESULT disk_writep (
+	const BYTE *buff,	/* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
+	DWORD sa			/* Number of bytes to send, Sector number (LBA) or zero */
+)
+{
+	DRESULT res;
+	WORD bc;
+	static WORD wc;
+
+	res = RES_ERROR;
+
+	if (buff) {		/* Send data bytes */
+		bc = (WORD)sa;
+		while (bc && wc) {		/* Send data bytes to the card */
+			xmit_spi(*buff++);
+			wc--; bc--;
+		}
+		res = RES_OK;
+	} else {
+		if (sa) {	/* Initiate sector write process */
+			if (!(CardType & CT_BLOCK)) sa *= 512;	/* Convert to byte address if needed */
+			if (send_cmd(CMD24, sa) == 0) {			/* WRITE_SINGLE_BLOCK */
+				xmit_spi(0xFF); xmit_spi(0xFE);		/* Data block header */
+				wc = 512;							/* Set byte counter */
+				res = RES_OK;
+			}
+		} else {	/* Finalize sector write process */
+			bc = wc + 2;
+			while (bc--) xmit_spi(0);	/* Fill left bytes and CRC with zeros */
+			if ((rcv_spi() & 0x1F) == 0x05) {	/* Receive data resp and wait for end of write process in timeout of 500ms */
+				for (bc = 5000; rcv_spi() != 0xFF && bc; bc--) dly_100us();	/* Wait ready */
+				if (bc) res = RES_OK;
+			}
+			DESELECT();
+			rcv_spi();
+		}
+	}
+
+	return res;
+}
+#endif
diff -r 000000000000 -r 845390b117a7 mmcPinConfig.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmcPinConfig.h	Fri May 09 19:41:49 2014 +0000
@@ -0,0 +1,10 @@
+#ifndef MMCPINCONFIG_H
+#define MMCPINCONFIG_H
+
+// pin configurations
+#define MMC_MISO dp1
+#define MMC_MOSI dp2
+#define MMC_SCLK dp6
+#define MMC_CS dp4
+
+#endif
diff -r 000000000000 -r 845390b117a7 pff.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pff.cpp	Fri May 09 19:41:49 2014 +0000
@@ -0,0 +1,1113 @@
+/*----------------------------------------------------------------------------/
+/  Petit FatFs - FAT file system module  R0.02a                (C)ChaN, 2010
+/-----------------------------------------------------------------------------/
+/ Petit FatFs module is an open source software to implement FAT file system to
+/ small embedded systems. This is a free software and is opened for education,
+/ research and commercial developments under license policy of following trems.
+/
+/  Copyright (C) 2010, ChaN, all right reserved.
+/
+/ * The Petit FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/   personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/-----------------------------------------------------------------------------/
+/ Jun 15,'09  R0.01a  First release. (Branched from FatFs R0.07b.)
+/
+/ Dec 14,'09  R0.02   Added multiple code page support.
+/                     Added write funciton.
+/                     Changed stream read mode interface.
+/ Dec 07,'10  R0.02a  Added some configuration options.
+/                     Fixed fails to open objects with DBCS character.
+/----------------------------------------------------------------------------*/
+
+#include "pff.h"		/* Petit FatFs configurations and declarations */
+#include "diskio.h"		/* Declarations of low level disk I/O functions */
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+
+#if _FS_FAT32
+#define LD_CLUST(dir)	(((DWORD)LD_WORD(dir+PFFDIR_FstClusHI)<<16) | LD_WORD(dir+PFFDIR_FstClusLO))
+#else
+#define LD_CLUST(dir)	LD_WORD(dir+PFFDIR_FstClusLO)
+#endif
+
+
+/*--------------------------------------------------------*/
+/* DBCS code ranges and SBCS extend char conversion table */
+
+#if _CODE_PAGE == 932	/* Japanese Shift-JIS */
+#define _DF1S	0x81	/* DBC 1st byte range 1 start */
+#define _DF1E	0x9F	/* DBC 1st byte range 1 end */
+#define _DF2S	0xE0	/* DBC 1st byte range 2 start */
+#define _DF2E	0xFC	/* DBC 1st byte range 2 end */
+#define _DS1S	0x40	/* DBC 2nd byte range 1 start */
+#define _DS1E	0x7E	/* DBC 2nd byte range 1 end */
+#define _DS2S	0x80	/* DBC 2nd byte range 2 start */
+#define _DS2E	0xFC	/* DBC 2nd byte range 2 end */
+
+#elif _CODE_PAGE == 936	/* Simplified Chinese GBK */
+#define _DF1S	0x81
+#define _DF1E	0xFE
+#define _DS1S	0x40
+#define _DS1E	0x7E
+#define _DS2S	0x80
+#define _DS2E	0xFE
+
+#elif _CODE_PAGE == 949	/* Korean */
+#define _DF1S	0x81
+#define _DF1E	0xFE
+#define _DS1S	0x41
+#define _DS1E	0x5A
+#define _DS2S	0x61
+#define _DS2E	0x7A
+#define _DS3S	0x81
+#define _DS3E	0xFE
+
+#elif _CODE_PAGE == 950	/* Traditional Chinese Big5 */
+#define _DF1S	0x81
+#define _DF1E	0xFE
+#define _DS1S	0x40
+#define _DS1E	0x7E
+#define _DS2S	0xA1
+#define _DS2E	0xFE
+
+#elif _CODE_PAGE == 437	/* U.S. (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 720	/* Arabic (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 737	/* Greek (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
+				0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 775	/* Baltic (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 850	/* Multilingual Latin 1 (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+				0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 852	/* Latin 2 (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
+				0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
+
+#elif _CODE_PAGE == 855	/* Cyrillic (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
+				0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
+				0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 857	/* Turkish (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
+				0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 858	/* Multilingual Latin 1 + Euro (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+				0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 862	/* Hebrew (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 866	/* Russian (OEM) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 874	/* Thai (OEM, Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+				0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
+
+#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
+				0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1253 /* Greek (Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
+				0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
+
+#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+				0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
+#define _DF1S	0
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
+				0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
+
+#elif _CODE_PAGE == 1	/* ASCII (for only non-LFN cfg) */
+#define _DF1S	0
+
+#else
+#error Unknown code page
+
+#endif
+
+
+
+/* Character code support macros */
+
+#define IsUpper(c)	(((c)>='A')&&((c)<='Z'))
+#define IsLower(c)	(((c)>='a')&&((c)<='z'))
+
+#if _DF1S		/* DBCS configuration */
+
+#ifdef _DF2S	/* Two 1st byte areas */
+#define IsDBCS1(c)	(((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
+#else			/* One 1st byte area */
+#define IsDBCS1(c)	((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
+#endif
+
+#ifdef _DS3S	/* Three 2nd byte areas */
+#define IsDBCS2(c)	(((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
+#else			/* Two 2nd byte areas */
+#define IsDBCS2(c)	(((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
+#endif
+
+#else			/* SBCS configuration */
+
+#define IsDBCS1(c)	0
+#define IsDBCS2(c)	0
+
+#endif /* _DF1S */
+
+
+/* FatFs refers the members in the FAT structures with byte offset instead
+/ of structure member because there are incompatibility of the packing option
+/ between various compilers. */
+
+#define BS_jmpBoot			0
+#define BS_OEMName			3
+#define BPB_BytsPerSec		11
+#define BPB_SecPerClus		13
+#define BPB_RsvdSecCnt		14
+#define BPB_NumFATs			16
+#define BPB_RootEntCnt		17
+#define BPB_TotSec16		19
+#define BPB_Media			21
+#define BPB_FATSz16			22
+#define BPB_SecPerTrk		24
+#define BPB_NumHeads		26
+#define BPB_HiddSec			28
+#define BPB_TotSec32		32
+#define BS_55AA				510
+
+#define BS_DrvNum			36
+#define BS_BootSig			38
+#define BS_VolID			39
+#define BS_VolLab			43
+#define BS_FilSysType		54
+
+#define BPB_FATSz32			36
+#define BPB_ExtFlags		40
+#define BPB_FSVer			42
+#define BPB_RootClus		44
+#define BPB_FSInfo			48
+#define BPB_BkBootSec		50
+#define BS_DrvNum32			64
+#define BS_BootSig32		66
+#define BS_VolID32			67
+#define BS_VolLab32			71
+#define BS_FilSysType32		82
+
+#define MBR_Table			446
+
+#define	PFFDIR_Name			0
+#define	PFFDIR_Attr			11
+#define	PFFDIR_NTres			12
+#define	PFFDIR_CrtTime			14
+#define	PFFDIR_CrtDate			16
+#define	PFFDIR_FstClusHI		20
+#define	PFFDIR_WrtTime			22
+#define	PFFDIR_WrtDate			24
+#define	PFFDIR_FstClusLO		26
+#define	PFFDIR_FileSize		28
+
+
+
+/*--------------------------------------------------------------------------
+
+   Private Functions
+
+---------------------------------------------------------------------------*/
+
+
+static
+FATFS *FatFs;	/* Pointer to the file system object (logical drive) */
+
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, int cnt) {
+	char *d = (char*)dst;
+	while (cnt--) *d++ = (char)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, int cnt) {
+	const char *d = (const char *)dst, *s = (const char *)src;
+	int r = 0;
+	while (cnt-- && (r = *d++ - *s++) == 0) ;
+	return r;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry                                */
+/*-----------------------------------------------------------------------*/
+
+static
+CLUST get_fat (	/* 1:IO error, Else:Cluster status */
+	CLUST clst	/* Cluster# to get the link information */
+)
+{
+	WORD wc, bc, ofs;
+	BYTE buf[4];
+	FATFS *fs = FatFs;
+
+
+	if (clst < 2 || clst >= fs->n_fatent)	/* Range check */
+		return 1;
+
+	switch (fs->fs_type) {
+#if _FS_FAT12
+	case FS_FAT12 :
+		bc = (WORD)clst; bc += bc / 2;
+		ofs = bc % 512; bc /= 512;
+		if (ofs != 511) {
+			if (disk_readp(buf, fs->fatbase + bc, ofs, 2)) break;
+		} else {
+			if (disk_readp(buf, fs->fatbase + bc, 511, 1)) break;
+			if (disk_readp(buf+1, fs->fatbase + bc + 1, 0, 1)) break;
+		}
+		wc = LD_WORD(buf);
+		return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+#endif
+	case FS_FAT16 :
+		if (disk_readp(buf, fs->fatbase + clst / 256, (WORD)(((WORD)clst % 256) * 2), 2)) break;
+		return LD_WORD(buf);
+#if _FS_FAT32
+	case FS_FAT32 :
+		if (disk_readp(buf, fs->fatbase + clst / 128, (WORD)(((WORD)clst % 128) * 4), 4)) break;
+		return LD_DWORD(buf) & 0x0FFFFFFF;
+#endif
+	}
+
+	return 1;	/* An error occured at the disk I/O layer */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster#                                             */
+/*-----------------------------------------------------------------------*/
+
+static
+DWORD clust2sect (	/* !=0: Sector number, 0: Failed - invalid cluster# */
+	CLUST clst		/* Cluster# to be converted */
+)
+{
+	FATFS *fs = FatFs;
+
+
+	clst -= 2;
+	if (clst >= (fs->n_fatent - 2)) return 0;		/* Invalid cluster# */
+	return (DWORD)clst * fs->csize + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Rewind directory index                           */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_rewind (
+	PFFDIR *dj			/* Pointer to directory object */
+)
+{
+	CLUST clst;
+	FATFS *fs = FatFs;
+
+
+	dj->index = 0;
+	clst = dj->sclust;
+	if (clst == 1 || clst >= fs->n_fatent)	/* Check start cluster range */
+		return FR_DISK_ERR;
+	if (_FS_FAT32 && !clst && fs->fs_type == FS_FAT32)	/* Replace cluster# 0 with root cluster# if in FAT32 */
+		clst = (CLUST)fs->dirbase;
+	dj->clust = clst;						/* Current cluster */
+	dj->sect = clst ? clust2sect(clst) : fs->dirbase;	/* Current sector */
+
+	return FR_OK;	/* Seek succeeded */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Move directory index next                        */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_next (	/* FR_OK:Succeeded, FR_NO_FILE:End of table */
+	PFFDIR *dj			/* Pointer to directory object */
+)
+{
+	CLUST clst;
+	WORD i;
+	FATFS *fs = FatFs;
+
+
+	i = dj->index + 1;
+	if (!i || !dj->sect)	/* Report EOT when index has reached 65535 */
+		return FR_NO_FILE;
+
+	if (!(i % 16)) {		/* Sector changed? */
+		dj->sect++;			/* Next sector */
+
+		if (dj->clust == 0) {	/* Static table */
+			if (i >= fs->n_rootdir)	/* Report EOT when end of table */
+				return FR_NO_FILE;
+		}
+		else {					/* Dynamic table */
+			if (((i / 16) & (fs->csize-1)) == 0) {	/* Cluster changed? */
+				clst = get_fat(dj->clust);		/* Get next cluster */
+				if (clst <= 1) return FR_DISK_ERR;
+				if (clst >= fs->n_fatent)		/* When it reached end of dynamic table */
+					return FR_NO_FILE;			/* Report EOT */
+				dj->clust = clst;				/* Initialize data for new cluster */
+				dj->sect = clust2sect(clst);
+			}
+		}
+	}
+
+	dj->index = i;
+
+	return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Find an object in the directory                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_find (
+	PFFDIR *dj,		/* Pointer to the directory object linked to the file name */
+	BYTE *dir		/* 32-byte working buffer */
+)
+{
+	FRESULT res;
+	BYTE c;
+
+
+	res = dir_rewind(dj);			/* Rewind directory object */
+	if (res != FR_OK) return res;
+
+	do {
+		res = disk_readp(dir, dj->sect, (WORD)((dj->index % 16) * 32), 32)	/* Read an entry */
+			? FR_DISK_ERR : FR_OK;
+		if (res != FR_OK) break;
+		c = dir[PFFDIR_Name];	/* First character */
+		if (c == 0) { res = FR_NO_FILE; break; }	/* Reached to end of table */
+		if (!(dir[PFFDIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
+			break;
+		res = dir_next(dj);					/* Next entry */
+	} while (res == FR_OK);
+
+	return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory                                     */
+/*-----------------------------------------------------------------------*/
+#if _USE_DIR
+static
+FRESULT dir_read (
+	PFFDIR *dj,		/* Pointer to the directory object to store read object name */
+	BYTE *dir		/* 32-byte working buffer */
+)
+{
+	FRESULT res;
+	BYTE a, c;
+
+
+	res = FR_NO_FILE;
+	while (dj->sect) {
+		res = disk_readp(dir, dj->sect, (WORD)((dj->index % 16) * 32), 32)	/* Read an entry */
+			? FR_DISK_ERR : FR_OK;
+		if (res != FR_OK) break;
+		c = dir[PFFDIR_Name];
+		if (c == 0) { res = FR_NO_FILE; break; }	/* Reached to end of table */
+		a = dir[PFFDIR_Attr] & AM_MASK;
+		if (c != 0xE5 && c != '.' && !(a & AM_VOL))	/* Is it a valid entry? */
+			break;
+		res = dir_next(dj);			/* Next entry */
+		if (res != FR_OK) break;
+	}
+
+	if (res != FR_OK) dj->sect = 0;
+
+	return res;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form           */
+/*-----------------------------------------------------------------------*/
+
+#ifdef _EXCVT
+	static const BYTE cvt[] = _EXCVT;
+#endif
+
+static
+FRESULT create_name (
+	PFFDIR *dj,			/* Pointer to the directory object */
+	const char **path	/* Pointer to pointer to the segment in the path string */
+)
+{
+	BYTE c, d, ni, si, i, *sfn;
+	const char *p;
+
+	/* Create file name in directory form */
+	sfn = dj->fn;
+	mem_set(sfn, ' ', 11);
+	si = i = 0; ni = 8;
+	p = *path;
+	for (;;) {
+		c = p[si++];
+		if (c <= ' ' || c == '/') break;	/* Break on end of segment */
+		if (c == '.' || i >= ni) {
+			if (ni != 8 || c != '.') break;
+			i = 8; ni = 11;
+			continue;
+		}
+#ifdef _EXCVT
+		if (c >= 0x80)					/* To upper extended char (SBCS) */
+			c = cvt[c - 0x80];
+#endif
+		if (IsDBCS1(c) && i < ni - 1) {	/* DBC 1st byte? */
+			d = p[si++];				/* Get 2nd byte */
+			sfn[i++] = c;
+			sfn[i++] = d;
+		} else {						/* Single byte code */
+			if (IsLower(c)) c -= 0x20;	/* toupper */
+			sfn[i++] = c;
+		}
+	}
+	*path = &p[si];						/* Rerurn pointer to the next segment */
+
+	sfn[11] = (c <= ' ') ? 1 : 0;		/* Set last segment flag if end of path */
+
+	return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file information from directory entry                             */
+/*-----------------------------------------------------------------------*/
+#if _USE_DIR
+static
+void get_fileinfo (		/* No return code */
+	PFFDIR *dj,			/* Pointer to the directory object */
+	BYTE *dir,			/* 32-byte working buffer */
+	FILINFO *fno	 	/* Pointer to store the file information */
+)
+{
+	BYTE i, c;
+	char *p;
+
+
+	p = fno->fname;
+	if (dj->sect) {
+		for (i = 0; i < 8; i++) {	/* Copy file name body */
+			c = dir[i];
+			if (c == ' ') break;
+			if (c == 0x05) c = 0xE5;
+			*p++ = c;
+		}
+		if (dir[8] != ' ') {		/* Copy file name extension */
+			*p++ = '.';
+			for (i = 8; i < 11; i++) {
+				c = dir[i];
+				if (c == ' ') break;
+				*p++ = c;
+			}
+		}
+		fno->fattrib = dir[PFFDIR_Attr];				/* Attribute */
+		fno->fsize = LD_DWORD(dir+PFFDIR_FileSize);	/* Size */
+		fno->fdate = LD_WORD(dir+PFFDIR_WrtDate);		/* Date */
+		fno->ftime = LD_WORD(dir+PFFDIR_WrtTime);		/* Time */
+	}
+	*p = 0;
+}
+#endif /* _USE_DIR */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path                                                    */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path (	/* FR_OK(0): successful, !=0: error code */
+	PFFDIR *dj,			/* Directory object to return last directory and found object */
+	BYTE *dir,			/* 32-byte working buffer */
+	const char *path	/* Full-path string to find a file or directory */
+)
+{
+	FRESULT res;
+
+
+	while (*path == ' ') path++;		/* Skip leading spaces */
+	if (*path == '/') path++;			/* Strip heading separator */
+	dj->sclust = 0;						/* Set start directory (always root dir) */
+
+	if ((BYTE)*path <= ' ') {			/* Null path means the root directory */
+		res = dir_rewind(dj);
+		dir[0] = 0;
+
+	} else {							/* Follow path */
+		for (;;) {
+			res = create_name(dj, &path);	/* Get a segment */
+			if (res != FR_OK) break;
+			res = dir_find(dj, dir);		/* Find it */
+			if (res != FR_OK) {				/* Could not find the object */
+				if (res == FR_NO_FILE && !*(dj->fn+11))
+					res = FR_NO_PATH;
+				break;
+			}
+			if (*(dj->fn+11)) break;		/* Last segment match. Function completed. */
+			if (!(dir[PFFDIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
+				res = FR_NO_PATH; break;
+			}
+			dj->sclust = LD_CLUST(dir);
+		}
+	}
+
+	return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check a sector if it is an FAT boot record                            */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs (	/* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */
+	BYTE *buf,	/* Working buffer */
+	DWORD sect	/* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+	if (disk_readp(buf, sect, 510, 2))		/* Read the boot sector */
+		return 3;
+	if (LD_WORD(buf) != 0xAA55)				/* Check record signature */
+		return 2;
+
+	if (!disk_readp(buf, sect, BS_FilSysType, 2) && LD_WORD(buf) == 0x4146)	/* Check FAT12/16 */
+		return 0;
+	if (_FS_FAT32 && !disk_readp(buf, sect, BS_FilSysType32, 2) && LD_WORD(buf) == 0x4146)	/* Check FAT32 */
+		return 0;
+	return 1;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Locical Drive                                         */
+/*-----------------------------------------------------------------------*/
+
+FRESULT pf_mount (
+	FATFS *fs		/* Pointer to new file system object (NULL: Unmount) */
+)
+{
+	BYTE fmt, buf[36];
+	DWORD bsect, fsize, tsect, mclst;
+
+
+	FatFs = 0;
+	if (!fs) return FR_OK;				/* Unregister fs object */
+
+	if (disk_initialize() & STA_NOINIT)	/* Check if the drive is ready or not */
+		return FR_NOT_READY;
+
+	/* Search FAT partition on the drive */
+	bsect = 0;
+	fmt = check_fs(buf, bsect);			/* Check sector 0 as an SFD format */
+	if (fmt == 1) {						/* Not an FAT boot record, it may be FDISK format */
+		/* Check a partition listed in top of the partition table */
+		if (disk_readp(buf, bsect, MBR_Table, 16)) {	/* 1st partition entry */
+			fmt = 3;
+		} else {
+			if (buf[4]) {					/* Is the partition existing? */
+				bsect = LD_DWORD(&buf[8]);	/* Partition offset in LBA */
+				fmt = check_fs(buf, bsect);	/* Check the partition */
+			}
+		}
+	}
+	if (fmt == 3) return FR_DISK_ERR;
+	if (fmt) return FR_NO_FILESYSTEM;	/* No valid FAT patition is found */
+
+	/* Initialize the file system object */
+	if (disk_readp(buf, bsect, 13, sizeof(buf))) return FR_DISK_ERR;
+
+	fsize = LD_WORD(buf+BPB_FATSz16-13);				/* Number of sectors per FAT */
+	if (!fsize) fsize = LD_DWORD(buf+BPB_FATSz32-13);
+
+	fsize *= buf[BPB_NumFATs-13];						/* Number of sectors in FAT area */
+	fs->fatbase = bsect + LD_WORD(buf+BPB_RsvdSecCnt-13); /* FAT start sector (lba) */
+	fs->csize = buf[BPB_SecPerClus-13];					/* Number of sectors per cluster */
+	fs->n_rootdir = LD_WORD(buf+BPB_RootEntCnt-13);		/* Nmuber of root directory entries */
+	tsect = LD_WORD(buf+BPB_TotSec16-13);				/* Number of sectors on the file system */
+	if (!tsect) tsect = LD_DWORD(buf+BPB_TotSec32-13);
+	mclst = (tsect						/* Last cluster# + 1 */
+		- LD_WORD(buf+BPB_RsvdSecCnt-13) - fsize - fs->n_rootdir / 16
+		) / fs->csize + 2;
+	fs->n_fatent = (CLUST)mclst;
+
+	fmt = FS_FAT16;							/* Determine the FAT sub type */
+	if (mclst < 0xFF7) 						/* Number of clusters < 0xFF5 */
+#if _FS_FAT12
+		fmt = FS_FAT12;
+#else
+		return FR_NO_FILESYSTEM;
+#endif
+	if (mclst >= 0xFFF7)					/* Number of clusters >= 0xFFF5 */
+#if _FS_FAT32
+		fmt = FS_FAT32;
+#else
+		return FR_NO_FILESYSTEM;
+#endif
+
+	fs->fs_type = fmt;		/* FAT sub-type */
+	if (_FS_FAT32 && fmt == FS_FAT32)
+		fs->dirbase = LD_DWORD(buf+(BPB_RootClus-13));	/* Root directory start cluster */
+	else
+		fs->dirbase = fs->fatbase + fsize;				/* Root directory start sector (lba) */
+	fs->database = fs->fatbase + fsize + fs->n_rootdir / 16;	/* Data start sector (lba) */
+
+	fs->flag = 0;
+	FatFs = fs;
+
+	return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT pf_open (
+	const char *path	/* Pointer to the file name */
+)
+{
+	FRESULT res;
+	PFFDIR dj;
+	BYTE sp[12], dir[32];
+	FATFS *fs = FatFs;
+
+
+	if (!fs)						/* Check file system */
+		return FR_NOT_ENABLED;
+
+	fs->flag = 0;
+	dj.fn = sp;
+	res = follow_path(&dj, dir, path);	/* Follow the file path */
+	if (res != FR_OK) return res;		/* Follow failed */
+	if (!dir[0] || (dir[PFFDIR_Attr] & AM_DIR))	/* It is a directory */
+		return FR_NO_FILE;
+
+	fs->org_clust = LD_CLUST(dir);			/* File start cluster */
+	fs->fsize = LD_DWORD(dir+PFFDIR_FileSize);	/* File size */
+	fs->fptr = 0;						/* File pointer */
+	fs->flag = FA_OPENED;
+
+	return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File                                                             */
+/*-----------------------------------------------------------------------*/
+#if _USE_READ
+
+FRESULT pf_read (
+	void* buff,		/* Pointer to the read buffer (NULL:Forward data to the stream)*/
+	WORD btr,		/* Number of bytes to read */
+	WORD* br		/* Pointer to number of bytes read */
+)
+{
+	DRESULT dr;
+	CLUST clst;
+	DWORD sect, remain;
+	WORD rcnt;
+	BYTE cs, *rbuff = (BYTE *)buff;
+	FATFS *fs = FatFs;
+
+
+	*br = 0;
+	if (!fs) return FR_NOT_ENABLED;		/* Check file system */
+	if (!(fs->flag & FA_OPENED))		/* Check if opened */
+		return FR_NOT_OPENED;
+
+	remain = fs->fsize - fs->fptr;
+	if (btr > remain) btr = (WORD)remain;			/* Truncate btr by remaining bytes */
+
+	while (btr)	{									/* Repeat until all data transferred */
+		if ((fs->fptr % 512) == 0) {				/* On the sector boundary? */
+			cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1));	/* Sector offset in the cluster */
+			if (!cs) {								/* On the cluster boundary? */
+				clst = (fs->fptr == 0) ?			/* On the top of the file? */
+					fs->org_clust : get_fat(fs->curr_clust);
+				if (clst <= 1) goto fr_abort;
+				fs->curr_clust = clst;				/* Update current cluster */
+			}
+			sect = clust2sect(fs->curr_clust);		/* Get current sector */
+			if (!sect) goto fr_abort;
+			fs->dsect = sect + cs;
+		}
+		rcnt = (WORD)(512 - (fs->fptr % 512));		/* Get partial sector data from sector buffer */
+		if (rcnt > btr) rcnt = btr;
+		dr = disk_readp(!buff ? 0 : rbuff, fs->dsect, (WORD)(fs->fptr % 512), rcnt);
+		if (dr) goto fr_abort;
+		fs->fptr += rcnt; rbuff += rcnt;			/* Update pointers and counters */
+		btr -= rcnt; *br += rcnt;
+	}
+
+	return FR_OK;
+
+fr_abort:
+	fs->flag = 0;
+	return FR_DISK_ERR;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write File                                                            */
+/*-----------------------------------------------------------------------*/
+#if _USE_WRITE
+
+FRESULT pf_write (
+	const void* buff,	/* Pointer to the data to be written */
+	WORD btw,			/* Number of bytes to write (0:Finalize the current write operation) */
+	WORD* bw			/* Pointer to number of bytes written */
+)
+{
+	CLUST clst;
+	DWORD sect, remain;
+	const BYTE *p =(const BYTE *) buff;
+	BYTE cs;
+	WORD wcnt;
+	FATFS *fs = FatFs;
+
+
+	*bw = 0;
+	if (!fs) return FR_NOT_ENABLED;		/* Check file system */
+	if (!(fs->flag & FA_OPENED))		/* Check if opened */
+		return FR_NOT_OPENED;
+
+	if (!btw) {		/* Finalize request */
+		if ((fs->flag & FA__WIP) && disk_writep(0, 0)) goto fw_abort;
+		fs->flag &= ~FA__WIP;
+		return FR_OK;
+	} else {		/* Write data request */
+		if (!(fs->flag & FA__WIP))		/* Round-down fptr to the sector boundary */
+			fs->fptr &= 0xFFFFFE00;
+	}
+	remain = fs->fsize - fs->fptr;
+	if (btw > remain) btw = (WORD)remain;			/* Truncate btw by remaining bytes */
+
+	while (btw)	{									/* Repeat until all data transferred */
+		if (((WORD)fs->fptr % 512) == 0) {			/* On the sector boundary? */
+			cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1));	/* Sector offset in the cluster */
+			if (!cs) {								/* On the cluster boundary? */
+				clst = (fs->fptr == 0) ?			/* On the top of the file? */
+					fs->org_clust : get_fat(fs->curr_clust);
+				if (clst <= 1) goto fw_abort;
+				fs->curr_clust = clst;				/* Update current cluster */
+			}
+			sect = clust2sect(fs->curr_clust);		/* Get current sector */
+			if (!sect) goto fw_abort;
+			fs->dsect = sect + cs;
+			if (disk_writep(0, fs->dsect)) goto fw_abort;	/* Initiate a sector write operation */
+			fs->flag |= FA__WIP;
+		}
+		wcnt = 512 - ((WORD)fs->fptr % 512);		/* Number of bytes to write to the sector */
+		if (wcnt > btw) wcnt = btw;
+		if (disk_writep(p, wcnt)) goto fw_abort;	/* Send data to the sector */
+		fs->fptr += wcnt; p += wcnt;				/* Update pointers and counters */
+		btw -= wcnt; *bw += wcnt;
+		if (((WORD)fs->fptr % 512) == 0) {
+			if (disk_writep(0, 0)) goto fw_abort;	/* Finalize the currtent secter write operation */
+			fs->flag &= ~FA__WIP;
+		}
+	}
+
+	return FR_OK;
+
+fw_abort:
+	fs->flag = 0;
+	return FR_DISK_ERR;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer                                                 */
+/*-----------------------------------------------------------------------*/
+#if _USE_LSEEK
+
+FRESULT pf_lseek (
+	DWORD ofs		/* File pointer from top of file */
+)
+{
+	CLUST clst;
+	DWORD bcs, sect, ifptr;
+	FATFS *fs = FatFs;
+
+
+	if (!fs) return FR_NOT_ENABLED;		/* Check file system */
+	if (!(fs->flag & FA_OPENED))		/* Check if opened */
+			return FR_NOT_OPENED;
+
+	if (ofs > fs->fsize) ofs = fs->fsize;	/* Clip offset with the file size */
+	ifptr = fs->fptr;
+	fs->fptr = 0;
+	if (ofs > 0) {
+		bcs = (DWORD)fs->csize * 512;	/* Cluster size (byte) */
+		if (ifptr > 0 &&
+			(ofs - 1) / bcs >= (ifptr - 1) / bcs) {	/* When seek to same or following cluster, */
+			fs->fptr = (ifptr - 1) & ~(bcs - 1);	/* start from the current cluster */
+			ofs -= fs->fptr;
+			clst = fs->curr_clust;
+		} else {							/* When seek to back cluster, */
+			clst = fs->org_clust;			/* start from the first cluster */
+			fs->curr_clust = clst;
+		}
+		while (ofs > bcs) {				/* Cluster following loop */
+			clst = get_fat(clst);		/* Follow cluster chain */
+			if (clst <= 1 || clst >= fs->n_fatent) goto fe_abort;
+			fs->curr_clust = clst;
+			fs->fptr += bcs;
+			ofs -= bcs;
+		}
+		fs->fptr += ofs;
+		sect = clust2sect(clst);		/* Current sector */
+		if (!sect) goto fe_abort;
+		fs->dsect = sect + (fs->fptr / 512 & (fs->csize - 1));
+	}
+
+	return FR_OK;
+
+fe_abort:
+	fs->flag = 0;
+	return FR_DISK_ERR;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directroy Object                                             */
+/*-----------------------------------------------------------------------*/
+#if _USE_DIR
+
+FRESULT pf_opendir (
+	PFFDIR *dj,			/* Pointer to directory object to create */
+	const char *path	/* Pointer to the directory path */
+)
+{
+	FRESULT res;
+	BYTE sp[12], dir[32];
+	FATFS *fs = FatFs;
+
+
+	if (!fs) {				/* Check file system */
+		res = FR_NOT_ENABLED;
+	} else {
+		dj->fn = sp;
+		res = follow_path(dj, dir, path);		/* Follow the path to the directory */
+		if (res == FR_OK) {						/* Follow completed */
+			if (dir[0]) {						/* It is not the root dir */
+				if (dir[PFFDIR_Attr] & AM_DIR)		/* The object is a directory */
+					dj->sclust = LD_CLUST(dir);
+				else							/* The object is not a directory */
+					res = FR_NO_PATH;
+			}
+			if (res == FR_OK)
+				res = dir_rewind(dj);			/* Rewind dir */
+		}
+		if (res == FR_NO_FILE) res = FR_NO_PATH;
+	}
+
+	return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequense                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT pf_readdir (
+	PFFDIR *dj,			/* Pointer to the open directory object */
+	FILINFO *fno		/* Pointer to file information to return */
+)
+{
+	FRESULT res;
+	BYTE sp[12], dir[32];
+	FATFS *fs = FatFs;
+
+
+	if (!fs) {				/* Check file system */
+		res = FR_NOT_ENABLED;
+	} else {
+		dj->fn = sp;
+		if (!fno) {
+			res = dir_rewind(dj);
+		} else {
+			res = dir_read(dj, dir);
+			if (res == FR_NO_FILE) {
+				dj->sect = 0;
+				res = FR_OK;
+			}
+			if (res == FR_OK) {				/* A valid entry is found */
+				get_fileinfo(dj, dir, fno);	/* Get the object information */
+				res = dir_next(dj);			/* Increment index for next */
+				if (res == FR_NO_FILE) {
+					dj->sect = 0;
+					res = FR_OK;
+				}
+			}
+		}
+	}
+
+	return res;
+}
+
+#endif /* _USE_DIR */
+
diff -r 000000000000 -r 845390b117a7 pff.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pff.h	Fri May 09 19:41:49 2014 +0000
@@ -0,0 +1,192 @@
+/* PFF for mbed porting by Takuya Urakawa, 2013 */
+
+/*---------------------------------------------------------------------------/
+/  Petit FatFs - FAT file system module include file  R0.02a   (C)ChaN, 2010
+/----------------------------------------------------------------------------/
+/ Petit FatFs module is an open source software to implement FAT file system to
+/ small embedded systems. This is a free software and is opened for education,
+/ research and commercial developments under license policy of following trems.
+/
+/  Copyright (C) 2010, ChaN, all right reserved.
+/
+/ * The Petit FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/   personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/----------------------------------------------------------------------------*/
+
+#include "integer.h"
+
+/*---------------------------------------------------------------------------/
+/ Petit FatFs Configuration Options
+/
+/ CAUTION! Do not forget to make clean the project after any changes to
+/ the configuration options.
+/
+/----------------------------------------------------------------------------*/
+#ifndef _FATFS
+#define _FATFS
+
+#define	_USE_READ	1	/* 1:Enable pf_read() */
+
+#define	_USE_DIR	1	/* 1:Enable pf_opendir() and pf_readdir() */
+
+#define	_USE_LSEEK	1	/* 1:Enable pf_lseek() */
+
+#define	_USE_WRITE	1	/* 1:Enable pf_write() */
+
+#define _FS_FAT12	1	/* 1:Enable FAT12 support */
+#define _FS_FAT32	1	/* 1:Enable FAT32 support */
+
+
+#define	_CODE_PAGE	1
+/* Defines which code page is used for path name. Supported code pages are:
+/  932, 936, 949, 950, 437, 720, 737, 775, 850, 852, 855, 857, 858, 862, 866,
+/  874, 1250, 1251, 1252, 1253, 1254, 1255, 1257, 1258 and 1 (ASCII only).
+/  SBCS code pages except for 1 requiers a case conversion table. This
+/  might occupy 128 bytes on the RAM on some platforms, e.g. avr-gcc. */
+
+
+#define _WORD_ACCESS	0
+/* The _WORD_ACCESS option defines which access method is used to the word
+/  data in the FAT structure.
+/
+/   0: Byte-by-byte access. Always compatible with all platforms.
+/   1: Word access. Do not choose this unless following condition is met.
+/
+/  When the byte order on the memory is big-endian or address miss-aligned
+/  word access results incorrect behavior, the _WORD_ACCESS must be set to 0.
+/  If it is not the case, the value can also be set to 1 to improve the
+/  performance and code efficiency. */
+
+
+/* End of configuration options. Do not change followings without care.     */
+/*--------------------------------------------------------------------------*/
+
+
+
+#if _FS_FAT32
+#define	CLUST	DWORD
+#else
+#define	CLUST	WORD
+#endif
+
+/* File system object structure */
+
+typedef struct {
+	BYTE	fs_type;	/* FAT sub type */
+	BYTE	flag;		/* File status flags */
+	BYTE	csize;		/* Number of sectors per cluster */
+	BYTE	pad1;
+	WORD	n_rootdir;	/* Number of root directory entries (0 on FAT32) */
+	CLUST	n_fatent;	/* Number of FAT entries (= number of clusters + 2) */
+	DWORD	fatbase;	/* FAT start sector */
+	DWORD	dirbase;	/* Root directory start sector (Cluster# on FAT32) */
+	DWORD	database;	/* Data start sector */
+	DWORD	fptr;		/* File R/W pointer */
+	DWORD	fsize;		/* File size */
+	CLUST	org_clust;	/* File start cluster */
+	CLUST	curr_clust;	/* File current cluster */
+	DWORD	dsect;		/* File current data sector */
+} FATFS;
+
+
+
+/* Directory object structure */
+
+typedef struct {
+	WORD	index;		/* Current read/write index number */
+	BYTE*	fn;			/* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
+	CLUST	sclust;		/* Table start cluster (0:Static table) */
+	CLUST	clust;		/* Current cluster */
+	DWORD	sect;		/* Current sector */
+} PFFDIR;
+
+
+
+/* File status structure */
+
+typedef struct {
+	DWORD	fsize;		/* File size */
+	WORD	fdate;		/* Last modified date */
+	WORD	ftime;		/* Last modified time */
+	BYTE	fattrib;	/* Attribute */
+	char	fname[13];	/* File name */
+} FILINFO;
+
+
+
+/* File function return code (FRESULT) */
+
+typedef enum {
+	FR_OK = 0,			/* 0 */
+	FR_DISK_ERR,		/* 1 */
+	FR_NOT_READY,		/* 2 */
+	FR_NO_FILE,			/* 3 */
+	FR_NO_PATH,			/* 4 */
+	FR_NOT_OPENED,		/* 5 */
+	FR_NOT_ENABLED,		/* 6 */
+	FR_NO_FILESYSTEM	/* 7 */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* Petit FatFs module application interface                     */
+
+FRESULT pf_mount (FATFS*);						/* Mount/Unmount a logical drive */
+FRESULT pf_open (const char*);					/* Open a file */
+FRESULT pf_read (void*, WORD, WORD*);			/* Read data from the open file */
+FRESULT pf_write (const void*, WORD, WORD*);	/* Write data to the open file */
+FRESULT pf_lseek (DWORD);						/* Move file pointer of the open file */
+FRESULT pf_opendir (PFFDIR*, const char*);			/* Open a directory */
+FRESULT pf_readdir (PFFDIR*, FILINFO*);			/* Read a directory item from the open directory */
+
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address                                     */
+
+/* File status flag (FATFS.flag) */
+
+#define	FA_OPENED	0x01
+#define	FA_WPRT		0x02
+#define	FA__WIP		0x40
+
+
+/* FAT sub type (FATFS.fs_type) */
+
+#define FS_FAT12	1
+#define FS_FAT16	2
+#define FS_FAT32	3
+
+
+/* File attribute bits for directory entry */
+
+#define	AM_RDO	0x01	/* Read only */
+#define	AM_HID	0x02	/* Hidden */
+#define	AM_SYS	0x04	/* System */
+#define	AM_VOL	0x08	/* Volume label */
+#define AM_LFN	0x0F	/* LFN entry */
+#define AM_DIR	0x10	/* Directory */
+#define AM_ARC	0x20	/* Archive */
+#define AM_MASK	0x3F	/* Mask of defined bits */
+
+
+/*--------------------------------*/
+/* Multi-byte word access macros  */
+
+#if _WORD_ACCESS == 1	/* Enable word access to the FAT structure */
+#define	LD_WORD(ptr)		(WORD)(*(WORD*)(BYTE*)(ptr))
+#define	LD_DWORD(ptr)		(DWORD)(*(DWORD*)(BYTE*)(ptr))
+#define	ST_WORD(ptr,val)	*(WORD*)(BYTE*)(ptr)=(WORD)(val)
+#define	ST_DWORD(ptr,val)	*(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
+#else					/* Use byte-by-byte access to the FAT structure */
+#define	LD_WORD(ptr)		(WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
+#define	LD_DWORD(ptr)		(DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
+#define	ST_WORD(ptr,val)	*(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
+#define	ST_DWORD(ptr,val)	*(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
+#endif
+
+
+#endif /* _FATFS */