EA BaseBoard, playing wav, PC see\'s SD-card through USB port.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
Lerche
Date:
Tue Nov 22 05:45:58 2011 +0000
Commit message:
Thanks to those who provided EA_WavPlayer and USB_MSC

Changed in this revision

ChaNFS/CHAN_FS/diskio.c Show annotated file Show diff for this revision Revisions of this file
ChaNFS/CHAN_FS/diskio.h Show annotated file Show diff for this revision Revisions of this file
ChaNFS/CHAN_FS/ff.c Show annotated file Show diff for this revision Revisions of this file
ChaNFS/CHAN_FS/ff.h Show annotated file Show diff for this revision Revisions of this file
ChaNFS/CHAN_FS/ffconf.h Show annotated file Show diff for this revision Revisions of this file
ChaNFS/CHAN_FS/integer.h Show annotated file Show diff for this revision Revisions of this file
ChaNFS/CHAN_FS/option/ccsbcs.c Show annotated file Show diff for this revision Revisions of this file
ChaNFS/FATDirHandle.cpp Show annotated file Show diff for this revision Revisions of this file
ChaNFS/FATDirHandle.h Show annotated file Show diff for this revision Revisions of this file
ChaNFS/FATFileHandle.cpp Show annotated file Show diff for this revision Revisions of this file
ChaNFS/FATFileHandle.h Show annotated file Show diff for this revision Revisions of this file
ChaNFS/FATFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
ChaNFS/FATFileSystem.h Show annotated file Show diff for this revision Revisions of this file
ChaNFSSD/SDFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
ChaNFSSD/SDFileSystem.h Show annotated file Show diff for this revision Revisions of this file
FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBBusInterface.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBBusInterface_LPC11U.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBBusInterface_LPC17_LPC23.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBDescriptor.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBDevice.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBDevice.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBDevice_Types.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBEndpoints.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBEndpoints_LPC11U.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBDevice/USBEndpoints_LPC17_LPC23.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHID/USBHID.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHID/USBHID.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHID/USBHID_Types.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHID/USBKeyboard.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHID/USBKeyboard.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHID/USBMouse.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHID/USBMouse.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHID/USBMouseKeyboard.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBHID/USBMouseKeyboard.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBMIDI/MIDIMessage.h Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBMIDI/USBMIDI.cpp Show annotated file Show diff for this revision Revisions of this file
USBDevice/USBMIDI/USBMIDI.h Show annotated file Show diff for this revision Revisions of this file
USBMSC.cpp Show annotated file Show diff for this revision Revisions of this file
USBMSC.h Show annotated file Show diff for this revision Revisions of this file
blockdev.h Show annotated file Show diff for this revision Revisions of this file
blockdev_sd.cpp Show annotated file Show diff for this revision Revisions of this file
dbg.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
msc_bot.cpp Show annotated file Show diff for this revision Revisions of this file
msc_bot.h Show annotated file Show diff for this revision Revisions of this file
msc_scsi.cpp Show annotated file Show diff for this revision Revisions of this file
msc_scsi.h Show annotated file Show diff for this revision Revisions of this file
wavplayer.cpp Show annotated file Show diff for this revision Revisions of this file
wavplayer.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/diskio.c	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,105 @@
+/*-----------------------------------------------------------------------*/
+/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2007        */
+/*-----------------------------------------------------------------------*/
+/* This is a stub disk I/O module that acts as front end of the existing */
+/* disk I/O modules and attach it to FatFs module with common interface. */
+/*-----------------------------------------------------------------------*/
+
+#include "diskio.h"
+#include <stdio.h>
+#include <string.h>
+#include "FATFileSystem.h"
+
+#include "mbed.h"
+
+DSTATUS disk_initialize (
+	BYTE drv				/* Physical drive nmuber (0..) */
+) 
+{
+	FFSDEBUG("disk_initialize on drv [%d]\n", drv);
+	return (DSTATUS)FATFileSystem::_ffs[drv]->disk_initialize();
+}
+
+DSTATUS disk_status (
+	BYTE drv		/* Physical drive nmuber (0..) */
+) 
+{
+	FFSDEBUG("disk_status on drv [%d]\n", drv);
+	return (DSTATUS)FATFileSystem::_ffs[drv]->disk_status();
+}
+
+DRESULT disk_read (
+	BYTE drv,		/* Physical drive nmuber (0..) */
+	BYTE *buff,		/* Data buffer to store read data */
+	DWORD sector,	/* Sector address (LBA) */
+	BYTE count		/* Number of sectors to read (1..255) */
+)
+{
+	FFSDEBUG("disk_read(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+	for(int s=sector; s<sector+count; s++) {
+		FFSDEBUG(" disk_read(sector %d)\n", s);
+		int res = FATFileSystem::_ffs[drv]->disk_read((char*)buff, s);
+		if(res) {
+			return RES_PARERR;
+		}
+		buff += 512;
+	}
+	return RES_OK;
+}
+
+#if _READONLY == 0
+DRESULT disk_write (
+	BYTE drv,			/* Physical drive nmuber (0..) */
+	const BYTE *buff,	/* Data to be written */
+	DWORD sector,		/* Sector address (LBA) */
+	BYTE count			/* Number of sectors to write (1..255) */
+)
+{
+	FFSDEBUG("disk_write(sector %d, count %d) on drv [%d]\n", sector, count, drv);
+	for(int s=sector; s<sector+count; s++) {
+		FFSDEBUG(" disk_write(sector %d)\n", s);
+		int res = FATFileSystem::_ffs[drv]->disk_write((char*)buff, sector);
+		if(res) {
+			return RES_PARERR;
+		}
+		buff += 512;
+	}
+	return RES_OK;
+}
+#endif /* _READONLY */
+
+DRESULT disk_ioctl (
+	BYTE drv,		/* Physical drive nmuber (0..) */
+	BYTE ctrl,		/* Control code */
+	void *buff		/* Buffer to send/receive control data */
+)
+{
+	FFSDEBUG("disk_ioctl(%d)\n", ctrl);
+	switch(ctrl) {
+		case CTRL_SYNC:
+			if(FATFileSystem::_ffs[drv] == NULL) {
+				return RES_NOTRDY;
+			} else if(FATFileSystem::_ffs[drv]->disk_sync()) {
+				return RES_ERROR;
+			} 
+			return RES_OK;
+		case GET_SECTOR_COUNT:
+			if(FATFileSystem::_ffs[drv] == NULL) {
+				return RES_NOTRDY;
+			} else {
+				int res = FATFileSystem::_ffs[drv]->disk_sectors();
+				if(res > 0) {
+					*((DWORD*)buff) = res; // minimum allowed
+					return RES_OK;
+				} else {
+					return RES_ERROR;
+				}
+			}
+		case GET_BLOCK_SIZE:
+			*((DWORD*)buff) = 1; // default when not known
+			return RES_OK;
+
+	}
+	return RES_PARERR;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/diskio.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,80 @@
+/*-----------------------------------------------------------------------
+/  Low level disk interface modlue include file
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO
+
+#define _READONLY	0	/* 1: Remove write functions */
+#define _USE_IOCTL	1	/* 1: Use disk_ioctl fucntion */
+
+#include "integer.h"
+
+
+/* Status of Disk Functions */
+typedef BYTE	DSTATUS;
+
+/* Results of Disk Functions */
+typedef enum {
+	RES_OK = 0,		/* 0: Successful */
+	RES_ERROR,		/* 1: R/W Error */
+	RES_WRPRT,		/* 2: Write Protected */
+	RES_NOTRDY,		/* 3: Not Ready */
+	RES_PARERR		/* 4: Invalid Parameter */
+} DRESULT;
+
+
+/*---------------------------------------*/
+/* Prototypes for disk control functions */
+
+int assign_drives (int, int);
+DSTATUS disk_initialize (BYTE);
+DSTATUS disk_status (BYTE);
+DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
+#if	_READONLY == 0
+DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
+#endif
+DRESULT disk_ioctl (BYTE, BYTE, void*);
+void	disk_timerproc (void);
+
+
+
+
+/* Disk Status Bits (DSTATUS) */
+
+#define STA_NOINIT		0x01	/* Drive not initialized */
+#define STA_NODISK		0x02	/* No medium in the drive */
+#define STA_PROTECT		0x04	/* Write protected */
+
+
+/* Command code for disk_ioctrl fucntion */
+
+/* Generic command (defined for FatFs) */
+#define CTRL_SYNC			0	/* Flush disk cache (for write functions) */
+#define GET_SECTOR_COUNT	1	/* Get media size (for only f_mkfs()) */
+#define GET_SECTOR_SIZE		2	/* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
+#define GET_BLOCK_SIZE		3	/* Get erase block size (for only f_mkfs()) */
+#define CTRL_ERASE_SECTOR	4	/* Force erased a block of sectors (for only _USE_ERASE) */
+
+/* Generic command */
+#define CTRL_POWER			5	/* Get/Set power status */
+#define CTRL_LOCK			6	/* Lock/Unlock media removal */
+#define CTRL_EJECT			7	/* Eject media */
+
+/* MMC/SDC specific ioctl command */
+#define MMC_GET_TYPE		10	/* Get card type */
+#define MMC_GET_CSD			11	/* Get CSD */
+#define MMC_GET_CID			12	/* Get CID */
+#define MMC_GET_OCR			13	/* Get OCR */
+#define MMC_GET_SDSTAT		14	/* Get SD status */
+
+/* ATA/CF specific ioctl command */
+#define ATA_GET_REV			20	/* Get F/W revision */
+#define ATA_GET_MODEL		21	/* Get model name */
+#define ATA_GET_SN			22	/* Get serial number */
+
+/* NAND specific ioctl command */
+#define NAND_FORMAT			30	/* Create physical format */
+
+
+#define _DISKIO
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/ff.c	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,3982 @@
+/*----------------------------------------------------------------------------/
+/  FatFs - FAT file system module  R0.08b                 (C)ChaN, 2011
+/-----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following terms.
+/
+/  Copyright (C) 2011, ChaN, all right reserved.
+/
+/ * The 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 products UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/-----------------------------------------------------------------------------/
+/ Feb 26,'06 R0.00  Prototype.
+/
+/ Apr 29,'06 R0.01  First stable version.
+/
+/ Jun 01,'06 R0.02  Added FAT12 support.
+/                   Removed unbuffered mode.
+/                   Fixed a problem on small (<32M) partition.
+/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
+/
+/ Sep 22,'06 R0.03  Added f_rename().
+/                   Changed option _FS_MINIMUM to _FS_MINIMIZE.
+/ Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast.
+/                   Fixed f_mkdir() creates incorrect directory on FAT32.
+/
+/ Feb 04,'07 R0.04  Supported multiple drive system.
+/                   Changed some interfaces for multiple drive system.
+/                   Changed f_mountdrv() to f_mount().
+/                   Added f_mkfs().
+/ Apr 01,'07 R0.04a Supported multiple partitions on a physical drive.
+/                   Added a capability of extending file size to f_lseek().
+/                   Added minimization level 3.
+/                   Fixed an endian sensitive code in f_mkfs().
+/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
+/                   Added FSInfo support.
+/                   Fixed DBCS name can result FR_INVALID_NAME.
+/                   Fixed short seek (<= csize) collapses the file object.
+/
+/ Aug 25,'07 R0.05  Changed arguments of f_read(), f_write() and f_mkfs().
+/                   Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
+/                   Fixed f_mkdir() on FAT32 creates incorrect directory.
+/ Feb 03,'08 R0.05a Added f_truncate() and f_utime().
+/                   Fixed off by one error at FAT sub-type determination.
+/                   Fixed btr in f_read() can be mistruncated.
+/                   Fixed cached sector is not flushed when create and close without write.
+/
+/ Apr 01,'08 R0.06  Added fputc(), fputs(), fprintf() and fgets().
+/                   Improved performance of f_lseek() on moving to the same or following cluster.
+/
+/ Apr 01,'09 R0.07  Merged Tiny-FatFs as a configuration option. (_FS_TINY)
+/                   Added long file name feature.
+/                   Added multiple code page feature.
+/                   Added re-entrancy for multitask operation.
+/                   Added auto cluster size selection to f_mkfs().
+/                   Added rewind option to f_readdir().
+/                   Changed result code of critical errors.
+/                   Renamed string functions to avoid name collision.
+/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
+/                   Added multiple sector size feature.
+/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
+/                   Fixed wrong cache control in f_lseek().
+/                   Added relative path feature.
+/                   Added f_chdir() and f_chdrive().
+/                   Added proper case conversion to extended char.
+/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
+/                   Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
+/                   Fixed name matching error on the 13 char boundary.
+/                   Added a configuration option, _LFN_UNICODE.
+/                   Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
+/
+/ May 15,'10 R0.08  Added a memory configuration option. (_USE_LFN = 3)
+/                   Added file lock feature. (_FS_SHARE)
+/                   Added fast seek feature. (_USE_FASTSEEK)
+/                   Changed some types on the API, XCHAR->TCHAR.
+/                   Changed fname member in the FILINFO structure on Unicode cfg.
+/                   String functions support UTF-8 encoding files on Unicode cfg.
+/ Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
+/                   Added sector erase feature. (_USE_ERASE)
+/                   Moved file lock semaphore table from fs object to the bss.
+/                   Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
+/                   Fixed f_mkfs() creates wrong FAT32 volume.
+/ Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write().
+/                   f_lseek() reports required table size on creating CLMP.
+/                   Extended format syntax of f_printf function.
+/                   Ignores duplicated directory separators in given path names.
+/---------------------------------------------------------------------------*/
+
+#include "ff.h"            /* FatFs configurations and declarations */
+#include "diskio.h"        /* Declarations of low level disk I/O functions */
+#include "mbed.h"
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+#if _FATFS != 8237
+#error Wrong include file (ff.h).
+#endif
+
+
+/* Definitions on sector size */
+#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096
+#error Wrong sector size.
+#endif
+#if _MAX_SS != 512
+#define    SS(fs)    ((fs)->ssize)    /* Multiple sector size */
+#else
+#define    SS(fs)    512U            /* Fixed sector size */
+#endif
+
+
+/* Reentrancy related */
+#if _FS_REENTRANT
+#if _USE_LFN == 1
+#error Static LFN work area must not be used in re-entrant configuration.
+#endif
+#define    ENTER_FF(fs)        { if (!lock_fs(fs)) return FR_TIMEOUT; }
+#define    LEAVE_FF(fs, res)    { unlock_fs(fs, res); return res; }
+#else
+#define    ENTER_FF(fs)
+#define LEAVE_FF(fs, res)    return res
+#endif
+
+#define    ABORT(fs, res)        { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
+
+
+/* File shareing feature */
+#if _FS_SHARE
+#if _FS_READONLY
+#error _FS_SHARE must be 0 on read-only cfg.
+#endif
+typedef struct {
+    FATFS *fs;                /* File ID 1, volume (NULL:blank entry) */
+    DWORD clu;                /* File ID 2, directory */
+    WORD idx;                /* File ID 3, directory index */
+    WORD ctr;                /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */
+} FILESEM;
+#endif
+
+
+/* Misc definitions */
+#define LD_CLUST(dir)    (((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO))
+#define ST_CLUST(dir,cl) {ST_WORD(dir+DIR_FstClusLO, cl); ST_WORD(dir+DIR_FstClusHI, (DWORD)cl>>16);}
+
+
+/* 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) */
+#if _USE_LFN
+#error Cannot use LFN feature without valid code page.
+#endif
+#define _DF1S    0
+
+#else
+#error Unknown code page
+
+#endif
+
+
+/* Character code support macros */
+#define IsUpper(c)    (((c)>='A')&&((c)<='Z'))
+#define IsLower(c)    (((c)>='a')&&((c)<='z'))
+#define IsDigit(c)    (((c)>='0')&&((c)<='9'))
+
+#if _DF1S        /* Code page is DBCS */
+
+#ifdef _DF2S    /* Two 1st byte areas */
+#define IsDBCS1(c)    (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
+#else            /* One 1st byte area */
+#define IsDBCS1(c)    ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
+#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            /* Code page is SBCS */
+
+#define IsDBCS1(c)    0
+#define IsDBCS2(c)    0
+
+#endif /* _DF1S */
+
+
+/* Name status flags */
+#define NS            11        /* Index of name status byte in fn[] */
+#define NS_LOSS        0x01    /* Out of 8.3 format */
+#define NS_LFN        0x02    /* Force to create LFN entry */
+#define NS_LAST        0x04    /* Last segment */
+#define NS_BODY        0x08    /* Lower case flag (body) */
+#define NS_EXT        0x10    /* Lower case flag (ext) */
+#define NS_DOT        0x20    /* Dot entry */
+
+
+/* FAT sub-type boundaries */
+/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
+#define MIN_FAT16    4086    /* Minimum number of clusters for FAT16 */
+#define    MIN_FAT32    65526    /* Minimum number of clusters for FAT32 */
+
+
+/* FatFs refers the members in the FAT structures as byte array instead of
+/ structure member because the structure is not binary compatible between
+/ different platforms */
+
+#define BS_jmpBoot            0    /* Jump instruction (3) */
+#define BS_OEMName            3    /* OEM name (8) */
+#define BPB_BytsPerSec        11    /* Sector size [byte] (2) */
+#define BPB_SecPerClus        13    /* Cluster size [sector] (1) */
+#define BPB_RsvdSecCnt        14    /* Size of reserved area [sector] (2) */
+#define BPB_NumFATs            16    /* Number of FAT copies (1) */
+#define BPB_RootEntCnt        17    /* Number of root dir entries for FAT12/16 (2) */
+#define BPB_TotSec16        19    /* Volume size [sector] (2) */
+#define BPB_Media            21    /* Media descriptor (1) */
+#define BPB_FATSz16            22    /* FAT size [sector] (2) */
+#define BPB_SecPerTrk        24    /* Track size [sector] (2) */
+#define BPB_NumHeads        26    /* Number of heads (2) */
+#define BPB_HiddSec            28    /* Number of special hidden sectors (4) */
+#define BPB_TotSec32        32    /* Volume size [sector] (4) */
+#define BS_DrvNum            36    /* Physical drive number (2) */
+#define BS_BootSig            38    /* Extended boot signature (1) */
+#define BS_VolID            39    /* Volume serial number (4) */
+#define BS_VolLab            43    /* Volume label (8) */
+#define BS_FilSysType        54    /* File system type (1) */
+#define BPB_FATSz32            36    /* FAT size [sector] (4) */
+#define BPB_ExtFlags        40    /* Extended flags (2) */
+#define BPB_FSVer            42    /* File system version (2) */
+#define BPB_RootClus        44    /* Root dir first cluster (4) */
+#define BPB_FSInfo            48    /* Offset of FSInfo sector (2) */
+#define BPB_BkBootSec        50    /* Offset of backup boot sectot (2) */
+#define BS_DrvNum32            64    /* Physical drive number (2) */
+#define BS_BootSig32        66    /* Extended boot signature (1) */
+#define BS_VolID32            67    /* Volume serial number (4) */
+#define BS_VolLab32            71    /* Volume label (8) */
+#define BS_FilSysType32        82    /* File system type (1) */
+#define    FSI_LeadSig            0    /* FSI: Leading signature (4) */
+#define    FSI_StrucSig        484    /* FSI: Structure signature (4) */
+#define    FSI_Free_Count        488    /* FSI: Number of free clusters (4) */
+#define    FSI_Nxt_Free        492    /* FSI: Last allocated cluster (4) */
+#define MBR_Table            446    /* MBR: Partition table offset (2) */
+#define    SZ_PTE                16    /* MBR: Size of a partition table entry */
+#define BS_55AA                510    /* Boot sector signature (2) */
+
+#define    DIR_Name            0    /* Short file name (11) */
+#define    DIR_Attr            11    /* Attribute (1) */
+#define    DIR_NTres            12    /* NT flag (1) */
+#define    DIR_CrtTime            14    /* Created time (2) */
+#define    DIR_CrtDate            16    /* Created date (2) */
+#define    DIR_FstClusHI        20    /* Higher 16-bit of first cluster (2) */
+#define    DIR_WrtTime            22    /* Modified time (2) */
+#define    DIR_WrtDate            24    /* Modified date (2) */
+#define    DIR_FstClusLO        26    /* Lower 16-bit of first cluster (2) */
+#define    DIR_FileSize        28    /* File size (4) */
+#define    LDIR_Ord            0    /* LFN entry order and LLE flag (1) */
+#define    LDIR_Attr            11    /* LFN attribute (1) */
+#define    LDIR_Type            12    /* LFN type (1) */
+#define    LDIR_Chksum            13    /* Sum of corresponding SFN entry */
+#define    LDIR_FstClusLO        26    /* Filled by zero (0) */
+#define    SZ_DIR                32        /* Size of a directory entry */
+#define    LLE                    0x40    /* Last long entry flag in LDIR_Ord */
+#define    DDE                    0xE5    /* Deleted directory enrty mark in DIR_Name[0] */
+#define    NDDE                0x05    /* Replacement of a character collides with DDE */
+
+
+/*------------------------------------------------------------*/
+/* Work area                                                  */
+
+#if _VOLUMES
+static
+FATFS *FatFs[_VOLUMES];    /* Pointer to the file system objects (logical drives) */
+#else
+#error Number of drives must not be 0.
+#endif
+
+static
+WORD Fsid;                /* File system mount ID */
+
+#if _FS_RPATH
+static
+BYTE CurrVol;            /* Current drive */
+#endif
+
+#if _FS_SHARE
+static
+FILESEM    Files[_FS_SHARE];    /* File lock semaphores */
+#endif
+
+#if _USE_LFN == 0            /* No LFN */
+#define    DEF_NAMEBUF            BYTE sfn[12]
+#define INIT_BUF(dobj)        (dobj).fn = sfn
+#define    FREE_BUF()
+
+#elif _USE_LFN == 1            /* LFN with static LFN working buffer */
+static WCHAR LfnBuf[_MAX_LFN+1];
+#define    DEF_NAMEBUF            BYTE sfn[12]
+#define INIT_BUF(dobj)        { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
+#define    FREE_BUF()
+
+#elif _USE_LFN == 2         /* LFN with dynamic LFN working buffer on the stack */
+#define    DEF_NAMEBUF            BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]
+#define INIT_BUF(dobj)        { (dobj).fn = sfn; (dobj).lfn = lbuf; }
+#define    FREE_BUF()
+
+#elif _USE_LFN == 3         /* LFN with dynamic LFN working buffer on the heap */
+#define    DEF_NAMEBUF            BYTE sfn[12]; WCHAR *lfn
+#define INIT_BUF(dobj)        { lfn = ff_memalloc((_MAX_LFN + 1) * 2); \
+                              if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \
+                              (dobj).lfn = lfn;    (dobj).fn = sfn; }
+#define    FREE_BUF()            ff_memfree(lfn)
+
+#else
+#error Wrong LFN configuration.
+#endif
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+//static FATFS *FatFs[_DRIVES];    /* Pointer to the file system objects (logical drives) */
+//static WORD fsid;                /* File system mount ID */
+
+/*-----------------------------------------------------------------------*/
+/* String functions                                                      */
+/*-----------------------------------------------------------------------*/
+
+/* Copy memory to memory */
+static
+void mem_cpy (void* dst, const void* src, UINT cnt) {
+    BYTE *d = (BYTE*)dst;
+    const BYTE *s = (const BYTE*)src;
+
+#if _WORD_ACCESS == 1
+    while (cnt >= sizeof(int)) {
+        *(int*)d = *(int*)s;
+        d += sizeof(int); s += sizeof(int);
+        cnt -= sizeof(int);
+    }
+#endif
+    while (cnt--)
+        *d++ = *s++;
+}
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, UINT cnt) {
+    BYTE *d = (BYTE*)dst;
+
+    while (cnt--)
+        *d++ = (BYTE)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, UINT cnt) {
+    const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
+    int r = 0;
+
+    while (cnt-- && (r = *d++ - *s++) == 0) ;
+    return r;
+}
+
+/* Check if chr is contained in the string */
+static
+int chk_chr (const char* str, int chr) {
+    while (*str && *str != chr) str++;
+    return *str;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Request/Release grant to access the volume                            */
+/*-----------------------------------------------------------------------*/
+#if _FS_REENTRANT
+
+static
+int lock_fs (
+    FATFS *fs        /* File system object */
+)
+{
+    return ff_req_grant(fs->sobj);
+}
+
+
+static
+void unlock_fs (
+    FATFS *fs,        /* File system object */
+    FRESULT res        /* Result code to be returned */
+)
+{
+    if (res != FR_NOT_ENABLED &&
+        res != FR_INVALID_DRIVE &&
+        res != FR_INVALID_OBJECT &&
+        res != FR_TIMEOUT) {
+        ff_rel_grant(fs->sobj);
+    }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* File shareing control functions                                       */
+/*-----------------------------------------------------------------------*/
+#if _FS_SHARE
+
+static
+FRESULT chk_lock (    /* Check if the file can be accessed */
+    DIR* dj,        /* Directory object pointing the file to be checked */
+    int acc            /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
+)
+{
+    UINT i, be;
+
+    /* Search file semaphore table */
+    for (i = be = 0; i < _FS_SHARE; i++) {
+        if (Files[i].fs) {    /* Existing entry */
+            if (Files[i].fs == dj->fs &&         /* Check if the file matched with an open file */
+                Files[i].clu == dj->sclust &&
+                Files[i].idx == dj->index) break;
+        } else {            /* Blank entry */
+            be++;
+        }
+    }
+    if (i == _FS_SHARE)    /* The file is not opened */
+        return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES;    /* Is there a blank entry for new file? */
+
+    /* The file has been opened. Reject any open against writing file and all write mode open */
+    return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
+}
+
+
+static
+int enq_lock (    /* Check if an entry is available for a new file */
+    FATFS* fs    /* File system object */
+)
+{
+    UINT i;
+
+    for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ;
+    return (i == _FS_SHARE) ? 0 : 1;
+}
+
+
+static
+UINT inc_lock (    /* Increment file open counter and returns its index (0:int error) */
+    DIR* dj,    /* Directory object pointing the file to register or increment */
+    int acc        /* Desired access mode (0:Read, !0:Write) */
+)
+{
+    UINT i;
+
+
+    for (i = 0; i < _FS_SHARE; i++) {    /* Find the file */
+        if (Files[i].fs == dj->fs &&
+            Files[i].clu == dj->sclust &&
+            Files[i].idx == dj->index) break;
+    }
+
+    if (i == _FS_SHARE) {                /* Not opened. Register it as new. */
+        for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ;
+        if (i == _FS_SHARE) return 0;    /* No space to register (int err) */
+        Files[i].fs = dj->fs;
+        Files[i].clu = dj->sclust;
+        Files[i].idx = dj->index;
+        Files[i].ctr = 0;
+    }
+
+    if (acc && Files[i].ctr) return 0;    /* Access violation (int err) */
+
+    Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1;    /* Set semaphore value */
+
+    return i + 1;
+}
+
+
+static
+FRESULT dec_lock (    /* Decrement file open counter */
+    UINT i            /* Semaphore index */
+)
+{
+    WORD n;
+    FRESULT res;
+
+
+    if (--i < _FS_SHARE) {
+        n = Files[i].ctr;
+        if (n == 0x100) n = 0;
+        if (n) n--;
+        Files[i].ctr = n;
+        if (!n) Files[i].fs = 0;
+        res = FR_OK;
+    } else {
+        res = FR_INT_ERR;
+    }
+    return res;
+}
+
+
+static
+void clear_lock (    /* Clear lock entries of the volume */
+    FATFS *fs
+)
+{
+    UINT i;
+
+    for (i = 0; i < _FS_SHARE; i++) {
+        if (Files[i].fs == fs) Files[i].fs = 0;
+    }
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change window offset                                                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT move_window (
+    FATFS *fs,        /* File system object */
+    DWORD sector    /* Sector number to make appearance in the fs->win[] */
+)                    /* Move to zero only writes back dirty window */
+{
+    DWORD wsect;
+
+
+    wsect = fs->winsect;
+    if (wsect != sector) {    /* Changed current window */
+#if !_FS_READONLY
+        if (fs->wflag) {    /* Write back dirty window if needed */
+            if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK)
+                return FR_DISK_ERR;
+            fs->wflag = 0;
+            if (wsect < (fs->fatbase + fs->fsize)) {    /* In FAT area */
+                BYTE nf;
+                for (nf = fs->n_fats; nf > 1; nf--) {    /* Reflect the change to all FAT copies */
+                    wsect += fs->fsize;
+                    disk_write(fs->drv, fs->win, wsect, 1);
+                }
+            }
+        }
+#endif
+        if (sector) {
+            if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK)
+                return FR_DISK_ERR;
+            fs->winsect = sector;
+        }
+    }
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Clean-up cached data                                                  */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT sync (    /* FR_OK: successful, FR_DISK_ERR: failed */
+    FATFS *fs    /* File system object */
+)
+{
+    FRESULT res;
+
+
+    res = move_window(fs, 0);
+    if (res == FR_OK) {
+    /* Update FSInfo sector if needed */
+    if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
+        fs->winsect = 0;
+            /* Create FSInfo structure */
+            mem_set(fs->win, 0, 512);
+            ST_WORD(fs->win+BS_55AA, 0xAA55);
+            ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
+            ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
+            ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
+            ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
+            /* Write it into the FSInfo sector */
+            disk_write(fs->drv, fs->win, fs->fsi_sector, 1);
+        fs->fsi_flag = 0;
+    }
+    /* Make sure that no pending write process in the physical drive */
+        if (disk_ioctl(fs->drv, CTRL_SYNC, (void*)0) != RES_OK)
+            res = FR_DISK_ERR;
+    }
+
+    return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster#                                             */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD clust2sect (    /* !=0: Sector number, 0: Failed - invalid cluster# */
+    FATFS *fs,        /* File system object */
+    DWORD clst        /* Cluster# to be converted */
+)
+{
+    clst -= 2;
+    if (clst >= (fs->n_fatent - 2)) return 0;        /* Invalid cluster# */
+    return clst * fs->csize + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry                                */
+/*-----------------------------------------------------------------------*/
+
+
+DWORD get_fat (    /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */
+    FATFS *fs,        /* File system object */
+    DWORD clst    /* Cluster# to get the link information */
+)
+{
+    UINT wc, bc;
+    BYTE *p;
+
+
+    if (clst < 2 || clst >= fs->n_fatent)    /* Chack range */
+        return 1;
+
+        switch (fs->fs_type) {
+        case FS_FAT12 :
+        bc = (UINT)clst; bc += bc / 2;
+        if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+        wc = fs->win[bc % SS(fs)]; bc++;
+        if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break;
+        wc |= fs->win[bc % SS(fs)] << 8;
+        return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+        case FS_FAT16 :
+        if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break;
+        p = &fs->win[clst * 2 % SS(fs)];
+        return LD_WORD(p);
+
+        case FS_FAT32 :
+        if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break;
+        p = &fs->win[clst * 4 % SS(fs)];
+        return LD_DWORD(p) & 0x0FFFFFFF;
+    }
+
+    return 0xFFFFFFFF;    /* An error occurred at the disk I/O layer */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Change value of a FAT entry                              */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+
+FRESULT put_fat (
+    FATFS *fs,        /* File system object */
+    DWORD clst,    /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */
+    DWORD val        /* New value to mark the cluster */
+)
+{
+    UINT bc;
+    BYTE *p;
+    FRESULT res;
+
+
+    if (clst < 2 || clst >= fs->n_fatent) {    /* Check range */
+        res = FR_INT_ERR;
+
+    } else {
+    switch (fs->fs_type) {
+    case FS_FAT12 :
+            bc = clst; bc += bc / 2;
+            res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+            if (res != FR_OK) break;
+            p = &fs->win[bc % SS(fs)];
+            *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
+        bc++;
+            fs->wflag = 1;
+            res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+            if (res != FR_OK) break;
+            p = &fs->win[bc % SS(fs)];
+            *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
+        break;
+
+    case FS_FAT16 :
+            res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
+            if (res != FR_OK) break;
+            p = &fs->win[clst * 2 % SS(fs)];
+            ST_WORD(p, (WORD)val);
+        break;
+
+    case FS_FAT32 :
+            res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
+            if (res != FR_OK) break;
+            p = &fs->win[clst * 4 % SS(fs)];
+            val |= LD_DWORD(p) & 0xF0000000;
+            ST_DWORD(p, val);
+        break;
+
+    default :
+            res = FR_INT_ERR;
+    }
+        fs->wflag = 1;
+    }
+
+    return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Remove a cluster chain                                 */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT remove_chain (
+    FATFS *fs,        /* File system object */
+    DWORD clst            /* Cluster# to remove a chain from */
+)
+{
+    FRESULT res;
+    DWORD nxt;
+#if _USE_ERASE
+    DWORD scl = clst, ecl = clst, resion[2];
+#endif
+
+    if (clst < 2 || clst >= fs->n_fatent) {    /* Check range */
+        res = FR_INT_ERR;
+
+    } else {
+        res = FR_OK;
+        while (clst < fs->n_fatent) {            /* Not a last link? */
+            nxt = get_fat(fs, clst);            /* Get cluster status */
+            if (nxt == 0) break;                /* Empty cluster? */
+            if (nxt == 1) { res = FR_INT_ERR; break; }    /* Internal error? */
+            if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }    /* Disk error? */
+            res = put_fat(fs, clst, 0);            /* Mark the cluster "empty" */
+            if (res != FR_OK) break;
+            if (fs->free_clust != 0xFFFFFFFF) {    /* Update FSInfo */
+            fs->free_clust++;
+            fs->fsi_flag = 1;
+            }
+#if _USE_ERASE
+            if (ecl + 1 == nxt) {    /* Next cluster is contiguous */
+                ecl = nxt;
+            } else {                /* End of contiguous clusters */ 
+                resion[0] = clust2sect(fs, scl);                    /* Start sector */
+                resion[1] = clust2sect(fs, ecl) + fs->csize - 1;    /* End sector */
+                disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, resion);        /* Erase the block */
+                scl = ecl = nxt;
+            }
+#endif
+            clst = nxt;    /* Next cluster */
+        }
+    }
+
+    return res;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Stretch or Create a cluster chain                      */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+DWORD create_chain (    /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
+    FATFS *fs,            /* File system object */
+    DWORD clst            /* Cluster# to stretch. 0 means create a new chain. */
+)
+{
+    DWORD cs, ncl, scl;
+    FRESULT res;
+
+
+    if (clst == 0) {        /* Create a new chain */
+        scl = fs->last_clust;            /* Get suggested start point */
+        if (!scl || scl >= fs->n_fatent) scl = 1;
+    }
+    else {                    /* Stretch the current chain */
+        cs = get_fat(fs, clst);            /* Check the cluster status */
+        if (cs < 2) return 1;            /* It is an invalid cluster */
+        if (cs < fs->n_fatent) return cs;    /* It is already followed by next cluster */
+        scl = clst;
+    }
+
+    ncl = scl;                /* Start cluster */
+    for (;;) {
+        ncl++;                            /* Next cluster */
+        if (ncl >= fs->n_fatent) {        /* Wrap around */
+            ncl = 2;
+            if (ncl > scl) return 0;    /* No free cluster */
+        }
+        cs = get_fat(fs, ncl);            /* Get the cluster status */
+        if (cs == 0) break;                /* Found a free cluster */
+        if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
+            return cs;
+        if (ncl == scl) return 0;        /* No free cluster */
+    }
+
+    res = put_fat(fs, ncl, 0x0FFFFFFF);    /* Mark the new cluster "last link" */
+    if (res == FR_OK && clst != 0) {
+        res = put_fat(fs, clst, ncl);    /* Link it to the previous one if needed */
+    }
+    if (res == FR_OK) {
+        fs->last_clust = ncl;            /* Update FSINFO */
+    if (fs->free_clust != 0xFFFFFFFF) {
+        fs->free_clust--;
+        fs->fsi_flag = 1;
+        }
+    } else {
+        ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
+    }
+
+    return ncl;        /* Return new cluster number or error code */
+}
+#endif /* !_FS_READONLY */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT handling - Convert offset into cluster with link map table        */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_FASTSEEK
+static
+DWORD clmt_clust (    /* <2:Error, >=2:Cluster number */
+    FIL* fp,        /* Pointer to the file object */
+    DWORD ofs        /* File offset to be converted to cluster# */
+)
+{
+    DWORD cl, ncl, *tbl;
+
+
+    tbl = fp->cltbl + 1;    /* Top of CLMT */
+    cl = ofs / SS(fp->fs) / fp->fs->csize;    /* Cluster order from top of the file */
+    for (;;) {
+        ncl = *tbl++;            /* Number of cluters in the fragment */
+        if (!ncl) return 0;        /* End of table? (error) */
+        if (cl < ncl) break;    /* In this fragment? */
+        cl -= ncl; tbl++;        /* Next fragment */
+    }
+    return cl + *tbl;    /* Return the cluster number */
+}
+#endif    /* _USE_FASTSEEK */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Set directory index                              */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_sdi (
+    DIR_t *dj,        /* Pointer to directory object */
+    WORD idx        /* Directory index number */
+)
+{
+    DWORD clst;
+    WORD ic;
+
+
+    dj->index = idx;
+    clst = dj->sclust;
+    if (clst == 1 || clst >= dj->fs->n_fatent)    /* Check start cluster range */
+        return FR_INT_ERR;
+    if (!clst && dj->fs->fs_type == FS_FAT32)    /* Replace cluster# 0 with root cluster# if in FAT32 */
+        clst = dj->fs->dirbase;
+
+    if (clst == 0) {    /* Static table (root-dir in FAT12/16) */
+        dj->clust = clst;
+        if (idx >= dj->fs->n_rootdir)        /* Index is out of range */
+            return FR_INT_ERR;
+        dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / SZ_DIR);    /* Sector# */
+    }
+    else {                /* Dynamic table (sub-dirs or root-dir in FAT32) */
+        ic = SS(dj->fs) / SZ_DIR * dj->fs->csize;    /* Entries per cluster */
+        while (idx >= ic) {    /* Follow cluster chain */
+            clst = get_fat(dj->fs, clst);                /* Get next cluster */
+            if (clst == 0xFFFFFFFF) return FR_DISK_ERR;    /* Disk error */
+            if (clst < 2 || clst >= dj->fs->n_fatent)    /* Reached to end of table or int error */
+                return FR_INT_ERR;
+            idx -= ic;
+        }
+        dj->clust = clst;
+        dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / SZ_DIR);    /* Sector# */
+    }
+
+    dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR;    /* Ptr to the entry in the 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, FR_DENIED:EOT and could not stretch */
+    DIR_t *dj,        /* Pointer to directory object */
+    int stretch        /* 0: Do not stretch table, 1: Stretch table if needed */
+)
+{
+    DWORD clst;
+    WORD i;
+
+
+    i = dj->index + 1;
+    if (!i || !dj->sect)    /* Report EOT when index has reached 65535 */
+        return FR_NO_FILE;
+
+    if (!(i % (SS(dj->fs) / SZ_DIR))) {    /* Sector changed? */
+        dj->sect++;                /* Next sector */
+
+        if (dj->clust == 0) {    /* Static table */
+            if (i >= dj->fs->n_rootdir)    /* Report EOT when end of table */
+                return FR_NO_FILE;
+        }
+        else {                    /* Dynamic table */
+            if (((i / (SS(dj->fs) / SZ_DIR)) & (dj->fs->csize - 1)) == 0) {    /* Cluster changed? */
+                clst = get_fat(dj->fs, dj->clust);                /* Get next cluster */
+                if (clst <= 1) return FR_INT_ERR;
+                if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+                if (clst >= dj->fs->n_fatent) {                    /* When it reached end of dynamic table */
+#if !_FS_READONLY
+                    BYTE c;
+                    if (!stretch) return FR_NO_FILE;            /* When do not stretch, report EOT */
+                    clst = create_chain(dj->fs, dj->clust);        /* Stretch cluster chain */
+                    if (clst == 0) return FR_DENIED;            /* No free cluster */
+                    if (clst == 1) return FR_INT_ERR;
+                    if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
+                    /* Clean-up stretched table */
+                    if (move_window(dj->fs, 0)) return FR_DISK_ERR;    /* Flush active window */
+                    mem_set(dj->fs->win, 0, SS(dj->fs));            /* Clear window buffer */
+                    dj->fs->winsect = clust2sect(dj->fs, clst);    /* Cluster start sector */
+                    for (c = 0; c < dj->fs->csize; c++) {        /* Fill the new cluster with 0 */
+                        dj->fs->wflag = 1;
+                        if (move_window(dj->fs, 0)) return FR_DISK_ERR;
+                        dj->fs->winsect++;
+                    }
+                    dj->fs->winsect -= c;                        /* Rewind window address */
+#else
+                    return FR_NO_FILE;            /* Report EOT */
+#endif
+            }
+                dj->clust = clst;                /* Initialize data for new cluster */
+                dj->sect = clust2sect(dj->fs, clst);
+        }
+    }
+    }
+
+    dj->index = i;
+    dj->dir = dj->fs->win + (i % (SS(dj->fs) / SZ_DIR)) * SZ_DIR;
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry   */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};    /* Offset of LFN chars in the directory entry */
+
+
+static
+int cmp_lfn (            /* 1:Matched, 0:Not matched */
+    WCHAR *lfnbuf,        /* Pointer to the LFN to be compared */
+    BYTE *dir            /* Pointer to the directory entry containing a part of LFN */
+)
+{
+    UINT i, s;
+    WCHAR wc, uc;
+
+
+    i = ((dir[LDIR_Ord] & ~LLE) - 1) * 13;    /* Get offset in the LFN buffer */
+    s = 0; wc = 1;
+    do {
+        uc = LD_WORD(dir+LfnOfs[s]);    /* Pick an LFN character from the entry */
+        if (wc) {    /* Last char has not been processed */
+            wc = ff_wtoupper(uc);        /* Convert it to upper case */
+            if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++]))    /* Compare it */
+                return 0;                /* Not matched */
+        } else {
+            if (uc != 0xFFFF) return 0;    /* Check filler */
+    }
+    } while (++s < 13);                /* Repeat until all chars in the entry are checked */
+
+    if ((dir[LDIR_Ord] & LLE) && wc && lfnbuf[i])    /* Last segment matched but different length */
+        return 0;
+
+    return 1;                        /* The part of LFN matched */
+        }
+
+
+
+static
+int pick_lfn (            /* 1:Succeeded, 0:Buffer overflow */
+    WCHAR *lfnbuf,        /* Pointer to the Unicode-LFN buffer */
+    BYTE *dir            /* Pointer to the directory entry */
+)
+{
+    UINT i, s;
+    WCHAR wc, uc;
+
+
+    i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13;    /* Offset in the LFN buffer */
+
+    s = 0; wc = 1;
+    do {
+        uc = LD_WORD(dir+LfnOfs[s]);        /* Pick an LFN character from the entry */
+        if (wc) {    /* Last char has not been processed */
+            if (i >= _MAX_LFN) return 0;    /* Buffer overflow? */
+            lfnbuf[i++] = wc = uc;            /* Store it */
+        } else {
+            if (uc != 0xFFFF) return 0;        /* Check filler */
+    }
+    } while (++s < 13);                        /* Read all character in the entry */
+
+    if (dir[LDIR_Ord] & LLE) {                /* Put terminator if it is the last LFN part */
+        if (i >= _MAX_LFN) return 0;        /* Buffer overflow? */
+        lfnbuf[i] = 0;
+}
+
+    return 1;
+}
+
+
+#if !_FS_READONLY
+static
+void fit_lfn (
+    const WCHAR *lfnbuf,    /* Pointer to the LFN buffer */
+    BYTE *dir,                /* Pointer to the directory entry */
+    BYTE ord,                /* LFN order (1-20) */
+    BYTE sum                /* SFN sum */
+)
+{
+    UINT i, s;
+    WCHAR wc;
+
+
+    dir[LDIR_Chksum] = sum;            /* Set check sum */
+    dir[LDIR_Attr] = AM_LFN;        /* Set attribute. LFN entry */
+    dir[LDIR_Type] = 0;
+    ST_WORD(dir+LDIR_FstClusLO, 0);
+
+    i = (ord - 1) * 13;                /* Get offset in the LFN buffer */
+    s = wc = 0;
+    do {
+        if (wc != 0xFFFF) wc = lfnbuf[i++];    /* Get an effective char */
+        ST_WORD(dir+LfnOfs[s], wc);    /* Put it */
+        if (!wc) wc = 0xFFFF;        /* Padding chars following last char */
+    } while (++s < 13);
+    if (wc == 0xFFFF || !lfnbuf[i]) ord |= LLE;    /* Bottom LFN part is the start of LFN sequence */
+    dir[LDIR_Ord] = ord;            /* Set the LFN order */
+}
+
+#endif
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create numbered name                                                  */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+void gen_numname (
+    BYTE *dst,            /* Pointer to generated SFN */
+    const BYTE *src,    /* Pointer to source SFN to be modified */
+    const WCHAR *lfn,    /* Pointer to LFN */
+    WORD seq            /* Sequence number */
+)
+{
+    BYTE ns[8], c;
+    UINT i, j;
+
+
+    mem_cpy(dst, src, 11);
+
+    if (seq > 5) {    /* On many collisions, generate a hash number instead of sequential number */
+        do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn);
+    }
+
+    /* itoa (hexdecimal) */
+    i = 7;
+    do {
+        c = (seq % 16) + '0';
+        if (c > '9') c += 7;
+        ns[i--] = c;
+        seq /= 16;
+    } while (seq);
+    ns[i] = '~';
+
+    /* Append the number */
+    for (j = 0; j < i && dst[j] != ' '; j++) {
+        if (IsDBCS1(dst[j])) {
+            if (j == i - 1) break;
+            j++;
+        }
+    }
+    do {
+        dst[j++] = (i < 8) ? ns[i++] : ' ';
+    } while (j < 8);
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Calculate sum of an SFN                                               */
+/*-----------------------------------------------------------------------*/
+#if _USE_LFN
+static
+BYTE sum_sfn (
+    const BYTE *dir        /* Ptr to directory entry */
+)
+{
+    BYTE sum = 0;
+    UINT n = 11;
+
+    do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
+    return sum;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Find an object in the directory                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_find (
+    DIR_t *dj            /* Pointer to the directory object linked to the file name */
+)
+{
+    FRESULT res;
+    BYTE c, *dir;
+#if _USE_LFN
+    BYTE a, ord, sum;
+#endif
+
+    res = dir_sdi(dj, 0);            /* Rewind directory object */
+    if (res != FR_OK) return res;
+
+#if _USE_LFN
+    ord = sum = 0xFF;
+#endif
+    do {
+        res = move_window(dj->fs, dj->sect);
+        if (res != FR_OK) break;
+        dir = dj->dir;                    /* Ptr to the directory entry of current index */
+        c = dir[DIR_Name];
+        if (c == 0) { res = FR_NO_FILE; break; }    /* Reached to end of table */
+#if _USE_LFN    /* LFN configuration */
+        a = dir[DIR_Attr] & AM_MASK;
+        if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) {    /* An entry without valid data */
+            ord = 0xFF;
+        } else {
+            if (a == AM_LFN) {            /* An LFN entry is found */
+                if (dj->lfn) {
+                    if (c & LLE) {        /* Is it start of LFN sequence? */
+                        sum = dir[LDIR_Chksum];
+                        c &= ~LLE; ord = c;    /* LFN start order */
+                        dj->lfn_idx = dj->index;
+        }
+                    /* Check validity of the LFN entry and compare it with given name */
+                    ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+            }
+            } else {                    /* An SFN entry is found */
+                if (!ord && sum == sum_sfn(dir)) break;    /* LFN matched? */
+                ord = 0xFF; dj->lfn_idx = 0xFFFF;    /* Reset LFN sequence */
+                if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break;    /* SFN matched? */
+            }
+        }
+#else        /* Non LFN configuration */
+        if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
+            break;
+#endif
+        res = dir_next(dj, 0);        /* Next entry */
+    } while (res == FR_OK);
+
+    return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory                                     */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+FRESULT dir_read (
+    DIR_t *dj            /* Pointer to the directory object that pointing the entry to be read */
+)
+{
+    FRESULT res;
+    BYTE c, *dir;
+#if _USE_LFN
+    BYTE a, ord = 0xFF, sum = 0xFF;
+#endif
+
+    res = FR_NO_FILE;
+    while (dj->sect) {
+        res = move_window(dj->fs, dj->sect);
+        if (res != FR_OK) break;
+        dir = dj->dir;                    /* Ptr to the directory entry of current index */
+        c = dir[DIR_Name];
+        if (c == 0) { res = FR_NO_FILE; break; }    /* Reached to end of table */
+#if _USE_LFN    /* LFN configuration */
+        a = dir[DIR_Attr] & AM_MASK;
+        if (c == DDE || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) {    /* An entry without valid data */
+            ord = 0xFF;
+        } else {
+            if (a == AM_LFN) {            /* An LFN entry is found */
+                if (c & LLE) {            /* Is it start of LFN sequence? */
+                    sum = dir[LDIR_Chksum];
+                    c &= ~LLE; ord = c;
+                    dj->lfn_idx = dj->index;
+        }
+                /* Check LFN validity and capture it */
+                ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+            } else {                    /* An SFN entry is found */
+                if (ord || sum != sum_sfn(dir))    /* Is there a valid LFN? */
+                    dj->lfn_idx = 0xFFFF;        /* It has no LFN. */
+                break;
+        }
+            }
+#else        /* Non LFN configuration */
+        if (c != DDE && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL))    /* Is it a valid entry? */
+            break;
+#endif
+        res = dir_next(dj, 0);                /* Next entry */
+        if (res != FR_OK) break;
+        }
+
+    if (res != FR_OK) dj->sect = 0;
+
+    return res;
+    }
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Register an object to the directory                                   */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY
+static
+FRESULT dir_register (    /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
+    DIR_t *dj                /* Target directory with object name to be created */
+)
+{
+    FRESULT res;
+    BYTE c, *dir;
+#if _USE_LFN    /* LFN configuration */
+    WORD n, ne, is;
+    BYTE sn[12], *fn, sum;
+    WCHAR *lfn;
+
+
+    fn = dj->fn; lfn = dj->lfn;
+    mem_cpy(sn, fn, 12);
+
+    if (_FS_RPATH && (sn[NS] & NS_DOT))        /* Cannot create dot entry */
+        return FR_INVALID_NAME;
+
+    if (sn[NS] & NS_LOSS) {            /* When LFN is out of 8.3 format, generate a numbered name */
+        fn[NS] = 0; dj->lfn = 0;            /* Find only SFN */
+        for (n = 1; n < 100; n++) {
+            gen_numname(fn, sn, lfn, n);    /* Generate a numbered name */
+            res = dir_find(dj);                /* Check if the name collides with existing SFN */
+            if (res != FR_OK) break;
+        }
+        if (n == 100) return FR_DENIED;        /* Abort if too many collisions */
+        if (res != FR_NO_FILE) return res;    /* Abort if the result is other than 'not collided' */
+        fn[NS] = sn[NS]; dj->lfn = lfn;
+}
+
+    if (sn[NS] & NS_LFN) {            /* When LFN is to be created, reserve an SFN + LFN entries. */
+        for (ne = 0; lfn[ne]; ne++) ;
+        ne = (ne + 25) / 13;
+    } else {                        /* Otherwise reserve only an SFN entry. */
+        ne = 1;
+    }
+
+    /* Reserve contiguous entries */
+    res = dir_sdi(dj, 0);
+    if (res != FR_OK) return res;
+    n = is = 0;
+    do {
+        res = move_window(dj->fs, dj->sect);
+        if (res != FR_OK) break;
+        c = *dj->dir;                /* Check the entry status */
+        if (c == DDE || c == 0) {    /* Is it a blank entry? */
+            if (n == 0) is = dj->index;    /* First index of the contiguous entry */
+            if (++n == ne) break;    /* A contiguous entry that required count is found */
+        } else {
+            n = 0;                    /* Not a blank entry. Restart to search */
+        }
+        res = dir_next(dj, 1);        /* Next entry with table stretch */
+    } while (res == FR_OK);
+
+    if (res == FR_OK && ne > 1) {    /* Initialize LFN entry if needed */
+        res = dir_sdi(dj, is);
+        if (res == FR_OK) {
+            sum = sum_sfn(dj->fn);    /* Sum of the SFN tied to the LFN */
+            ne--;
+            do {                    /* Store LFN entries in bottom first */
+                res = move_window(dj->fs, dj->sect);
+                if (res != FR_OK) break;
+                fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
+                dj->fs->wflag = 1;
+                res = dir_next(dj, 0);    /* Next entry */
+            } while (res == FR_OK && --ne);
+        }
+    }
+
+#else    /* Non LFN configuration */
+    res = dir_sdi(dj, 0);
+    if (res == FR_OK) {
+        do {    /* Find a blank entry for the SFN */
+            res = move_window(dj->fs, dj->sect);
+            if (res != FR_OK) break;
+            c = *dj->dir;
+            if (c == DDE || c == 0) break;    /* Is it a blank entry? */
+            res = dir_next(dj, 1);            /* Next entry with table stretch */
+        } while (res == FR_OK);
+    }
+#endif
+
+    if (res == FR_OK) {        /* Initialize the SFN entry */
+        res = move_window(dj->fs, dj->sect);
+        if (res == FR_OK) {
+            dir = dj->dir;
+            mem_set(dir, 0, SZ_DIR);    /* Clean the entry */
+            mem_cpy(dir, dj->fn, 11);    /* Put SFN */
+#if _USE_LFN
+            dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT);    /* Put NT flag */
+#endif
+            dj->fs->wflag = 1;
+        }
+    }
+
+    return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Remove an object from the directory                                   */
+/*-----------------------------------------------------------------------*/
+#if !_FS_READONLY && !_FS_MINIMIZE
+static
+FRESULT dir_remove (    /* FR_OK: Successful, FR_DISK_ERR: A disk error */
+    DIR_t *dj                /* Directory object pointing the entry to be removed */
+)
+{
+    FRESULT res;
+#if _USE_LFN    /* LFN configuration */
+    WORD i;
+
+    i = dj->index;    /* SFN index */
+    res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx));    /* Goto the SFN or top of the LFN entries */
+    if (res == FR_OK) {
+        do {
+            res = move_window(dj->fs, dj->sect);
+            if (res != FR_OK) break;
+            *dj->dir = DDE;            /* Mark the entry "deleted" */
+            dj->fs->wflag = 1;
+            if (dj->index >= i) break;    /* When reached SFN, all entries of the object has been deleted. */
+            res = dir_next(dj, 0);        /* Next entry */
+        } while (res == FR_OK);
+        if (res == FR_NO_FILE) res = FR_INT_ERR;
+    }
+
+#else            /* Non LFN configuration */
+    res = dir_sdi(dj, dj->index);
+    if (res == FR_OK) {
+        res = move_window(dj->fs, dj->sect);
+        if (res == FR_OK) {
+            *dj->dir = DDE;            /* Mark the entry "deleted" */
+            dj->fs->wflag = 1;
+        }
+    }
+#endif
+
+    return res;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form           */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT create_name (
+    DIR_t *dj,            /* Pointer to the directory object */
+    const TCHAR **path    /* Pointer to pointer to the segment in the path string */
+)
+{
+#ifdef _EXCVT
+    static const BYTE excvt[] = _EXCVT;    /* Upper conversion table for extended chars */
+#endif
+
+#if _USE_LFN    /* LFN configuration */
+    BYTE b, cf;
+    WCHAR w, *lfn;
+    UINT i, ni, si, di;
+    const TCHAR *p;
+
+    /* Create LFN in Unicode */
+    for (p = *path; *p == '/' || *p == '\\'; p++) ;    /* Strip duplicated separator */
+    lfn = dj->lfn;
+    si = di = 0;
+    for (;;) {
+        w = p[si++];                    /* Get a character */
+        if (w < ' ' || w == '/' || w == '\\') break;    /* Break on end of segment */
+        if (di >= _MAX_LFN)                /* Reject too long name */
+            return FR_INVALID_NAME;
+#if !_LFN_UNICODE
+        w &= 0xFF;
+        if (IsDBCS1(w)) {                /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+            b = (BYTE)p[si++];            /* Get 2nd byte */
+            if (!IsDBCS2(b))
+                return FR_INVALID_NAME;    /* Reject invalid sequence */
+            w = (w << 8) + b;            /* Create a DBC */
+        }
+        w = ff_convert(w, 1);            /* Convert ANSI/OEM to Unicode */
+        if (!w) return FR_INVALID_NAME;    /* Reject invalid code */
+#endif
+        if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
+            return FR_INVALID_NAME;
+        lfn[di++] = w;                    /* Store the Unicode char */
+    }
+    *path = &p[si];                        /* Return pointer to the next segment */
+    cf = (w < ' ') ? NS_LAST : 0;        /* Set last segment flag if end of path */
+#if _FS_RPATH
+    if ((di == 1 && lfn[di-1] == '.') || /* Is this a dot entry? */
+        (di == 2 && lfn[di-1] == '.' && lfn[di-2] == '.')) {
+        lfn[di] = 0;
+        for (i = 0; i < 11; i++)
+            dj->fn[i] = (i < di) ? '.' : ' ';
+        dj->fn[i] = cf | NS_DOT;        /* This is a dot entry */
+        return FR_OK;
+    }
+#endif
+    while (di) {                        /* Strip trailing spaces and dots */
+        w = lfn[di-1];
+        if (w != ' ' && w != '.') break;
+        di--;
+    }
+    if (!di) return FR_INVALID_NAME;    /* Reject nul string */
+
+    lfn[di] = 0;                        /* LFN is created */
+
+    /* Create SFN in directory form */
+    mem_set(dj->fn, ' ', 11);
+    for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ;    /* Strip leading spaces and dots */
+    if (si) cf |= NS_LOSS | NS_LFN;
+    while (di && lfn[di - 1] != '.') di--;    /* Find extension (di<=si: no extension) */
+
+    b = i = 0; ni = 8;
+    for (;;) {
+        w = lfn[si++];                    /* Get an LFN char */
+        if (!w) break;                    /* Break on end of the LFN */
+        if (w == ' ' || (w == '.' && si != di)) {    /* Remove spaces and dots */
+            cf |= NS_LOSS | NS_LFN; continue;
+        }
+
+        if (i >= ni || si == di) {        /* Extension or end of SFN */
+            if (ni == 11) {                /* Long extension */
+                cf |= NS_LOSS | NS_LFN; break;
+            }
+            if (si != di) cf |= NS_LOSS | NS_LFN;    /* Out of 8.3 format */
+            if (si > di) break;            /* No extension */
+            si = di; i = 8; ni = 11;    /* Enter extension section */
+            b <<= 2; continue;
+        }
+
+        if (w >= 0x80) {                /* Non ASCII char */
+#ifdef _EXCVT
+            w = ff_convert(w, 0);        /* Unicode -> OEM code */
+            if (w) w = excvt[w - 0x80];    /* Convert extended char to upper (SBCS) */
+#else
+            w = ff_convert(ff_wtoupper(w), 0);    /* Upper converted Unicode -> OEM code */
+#endif
+            cf |= NS_LFN;                /* Force create LFN entry */
+        }
+
+        if (_DF1S && w >= 0x100) {        /* Double byte char (always false on SBCS cfg) */
+            if (i >= ni - 1) {
+                cf |= NS_LOSS | NS_LFN; i = ni; continue;
+            }
+            dj->fn[i++] = (BYTE)(w >> 8);
+        } else {                        /* Single byte char */
+            if (!w || chk_chr("+,;=[]", w)) {    /* Replace illegal chars for SFN */
+                w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
+            } else {
+                if (IsUpper(w)) {        /* ASCII large capital */
+                    b |= 2;
+    } else {
+                    if (IsLower(w)) {    /* ASCII small capital */
+                        b |= 1; w -= 0x20;
+    }
+                }
+            }
+        }
+        dj->fn[i++] = (BYTE)w;
+    }
+
+    if (dj->fn[0] == DDE) dj->fn[0] = NDDE;    /* If the first char collides with deleted mark, replace it with 0x05 */
+
+    if (ni == 8) b <<= 2;
+    if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03)    /* Create LFN entry when there are composite capitals */
+        cf |= NS_LFN;
+    if (!(cf & NS_LFN)) {                        /* When LFN is in 8.3 format without extended char, NT flags are created */
+        if ((b & 0x03) == 0x01) cf |= NS_EXT;    /* NT flag (Extension has only small capital) */
+        if ((b & 0x0C) == 0x04) cf |= NS_BODY;    /* NT flag (Filename has only small capital) */
+    }
+
+    dj->fn[NS] = cf;    /* SFN is created */
+
+    return FR_OK;
+
+
+#else    /* Non-LFN configuration */
+    BYTE b, c, d, *sfn;
+    UINT ni, si, i;
+    const char *p;
+
+    /* Create file name in directory form */
+    for (p = *path; *p == '/' || *p == '\\'; p++) ;    /* Strip duplicated separator */
+    sfn = dj->fn;
+    mem_set(sfn, ' ', 11);
+    si = i = b = 0; ni = 8;
+#if _FS_RPATH
+    if (p[si] == '.') { /* Is this a dot entry? */
+    for (;;) {
+            c = (BYTE)p[si++];
+            if (c != '.' || si >= 3) break;
+            sfn[i++] = c;
+        }
+        if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
+        *path = &p[si];                                    /* Return pointer to the next segment */
+        sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT;    /* Set last segment flag if end of path */
+        return FR_OK;
+    }
+#endif
+        for (;;) {
+        c = (BYTE)p[si++];
+        if (c <= ' ' || c == '/' || c == '\\') break;    /* Break on end of segment */
+        if (c == '.' || i >= ni) {
+            if (ni != 8 || c != '.') return FR_INVALID_NAME;
+            i = 8; ni = 11;
+            b <<= 2; continue;
+        }
+        if (c >= 0x80) {                /* Extended char? */
+            b |= 3;                        /* Eliminate NT flag */
+#ifdef _EXCVT
+            c = excvt[c-0x80];            /* Upper conversion (SBCS) */
+#else
+#if !_DF1S    /* ASCII only cfg */
+            return FR_INVALID_NAME;
+#endif
+#endif
+        }
+        if (IsDBCS1(c)) {                /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+            d = (BYTE)p[si++];            /* Get 2nd byte */
+            if (!IsDBCS2(d) || i >= ni - 1)    /* Reject invalid DBC */
+                return FR_INVALID_NAME;
+            sfn[i++] = c;
+            sfn[i++] = d;
+        } else {                        /* Single byte code */
+            if (chk_chr("\"*+,:;<=>\?[]|\x7F", c))    /* Reject illegal chrs for SFN */
+                return FR_INVALID_NAME;
+            if (IsUpper(c)) {            /* ASCII large capital? */
+                b |= 2;
+            } else {
+                if (IsLower(c)) {        /* ASCII small capital? */
+                    b |= 1; c -= 0x20;
+                }
+            }
+            sfn[i++] = c;
+        }
+    }
+    *path = &p[si];                        /* Return pointer to the next segment */
+    c = (c <= ' ') ? NS_LAST : 0;        /* Set last segment flag if end of path */
+
+    if (!i) return FR_INVALID_NAME;        /* Reject nul string */
+    if (sfn[0] == DDE) sfn[0] = NDDE;    /* When first char collides with DDE, replace it with 0x05 */
+
+    if (ni == 8) b <<= 2;
+    if ((b & 0x03) == 0x01) c |= NS_EXT;    /* NT flag (Name extension has only small capital) */
+    if ((b & 0x0C) == 0x04) c |= NS_BODY;    /* NT flag (Name body has only small capital) */
+
+    sfn[NS] = c;        /* Store NT flag, File name is created */
+
+    return FR_OK;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file information from directory entry                             */
+/*-----------------------------------------------------------------------*/
+#if _FS_MINIMIZE <= 1
+static
+void get_fileinfo (        /* No return code */
+    DIR_t *dj,            /* Pointer to the directory object */
+    FILINFO *fno         /* Pointer to the file information to be filled */
+)
+{
+    UINT i;
+    BYTE nt, *dir;
+    TCHAR *p, c;
+    p = fno->fname;
+    
+    if (dj->sect) {
+        dir = dj->dir;
+        nt = dir[DIR_NTres];        /* NT flag */
+        for (i = 0; i < 8; i++) {    /* Copy name body */
+            c = dir[i];
+            if (c == ' ') break;
+            if (c == NDDE) c = (TCHAR)DDE;
+            if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
+#if _LFN_UNICODE
+            if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1]))
+                c = (c << 8) | dir[++i];
+            c = ff_convert(c, 1);
+            if (!c) c = '?';
+#endif
+            *p++ = c;
+        }
+        if (dir[8] != ' ') {        /* Copy name extension */
+            *p++ = '.';
+            for (i = 8; i < 11; i++) {
+                c = dir[i];
+                if (c == ' ') break;
+                if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
+#if _LFN_UNICODE
+                if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1]))
+                    c = (c << 8) | dir[++i];
+                c = ff_convert(c, 1);
+                if (!c) c = '?';
+#endif
+                *p++ = c;
+            }
+    }
+        fno->fattrib = dir[DIR_Attr];                /* Attribute */
+        fno->fsize = LD_DWORD(dir+DIR_FileSize);    /* Size */
+        fno->fdate = LD_WORD(dir+DIR_WrtDate);        /* Date */
+        fno->ftime = LD_WORD(dir+DIR_WrtTime);        /* Time */
+    }
+    *p = 0;        /* Terminate SFN str by a \0 */
+
+#if _USE_LFN
+    if (fno->lfname && fno->lfsize) {
+        TCHAR *tp = fno->lfname;
+        WCHAR w, *lfn;
+
+        i = 0;
+        if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
+            lfn = dj->lfn;
+            while ((w = *lfn++) != 0) {            /* Get an LFN char */
+#if !_LFN_UNICODE
+                w = ff_convert(w, 0);            /* Unicode -> OEM conversion */
+                if (!w) { i = 0; break; }        /* Could not convert, no LFN */
+                if (_DF1S && w >= 0x100)        /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
+                    tp[i++] = (TCHAR)(w >> 8);
+#endif
+                if (i >= fno->lfsize - 1) { i = 0; break; }    /* Buffer overflow, no LFN */
+                tp[i++] = (TCHAR)w;
+            }
+
+        }
+        tp[i] = 0;    /* Terminate the LFN str by a \0 */
+    }
+#endif
+}
+#endif /* _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path                                                    */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path (    /* FR_OK(0): successful, !=0: error code */
+    DIR_t *dj,            /* Directory object to return last directory and found object */
+    const TCHAR *path    /* Full-path string to find a file or directory */
+)
+{
+    FRESULT res;
+    BYTE *dir, ns;
+
+
+#if _FS_RPATH
+    if (*path == '/' || *path == '\\') { /* There is a heading separator */
+        path++;    dj->sclust = 0;        /* Strip it and start from the root dir */
+    } else {                            /* No heading separator */
+        dj->sclust = dj->fs->cdir;    /* Start from the current dir */
+    }
+#else
+    if (*path == '/' || *path == '\\')    /* Strip heading separator if exist */
+        path++;
+    dj->sclust = 0;                        /* Start from the root dir */
+#endif
+
+    if ((UINT)*path < ' ') {            /* Nul path means the start directory itself */
+        res = dir_sdi(dj, 0);
+        dj->dir = 0;
+
+    } else {                            /* Follow path */
+        for (;;) {
+            res = create_name(dj, &path);    /* Get a segment */
+            if (res != FR_OK) break;
+            res = dir_find(dj);                /* Find it */
+            ns = *(dj->fn+NS);
+            if (res != FR_OK) {                /* Failed to find the object */
+                if (res != FR_NO_FILE) break;    /* Abort if any hard error occured */
+                /* Object not found */
+                if (_FS_RPATH && (ns & NS_DOT)) {    /* If dot entry is not exit */
+                    dj->sclust = 0; dj->dir = 0;    /* It is the root dir */
+                    res = FR_OK;
+                    if (!(ns & NS_LAST)) continue;
+                } else {                            /* Could not find the object */
+                    if (!(ns & NS_LAST)) res = FR_NO_PATH;
+                }
+                break;
+            }
+            if (ns & NS_LAST) break;            /* Last segment match. Function completed. */
+            dir = dj->dir;                        /* There is next segment. Follow the sub directory */
+            if (!(dir[DIR_Attr] & AM_DIR)) {    /* Cannot follow because it is a file */
+                res = FR_NO_PATH; break;
+            }
+            dj->sclust = LD_CLUST(dir);
+        }
+    }
+
+    return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load boot record and check if it is an FAT boot record                */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs (    /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
+    FATFS *fs,    /* File system object */
+    DWORD sect    /* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+    if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK)    /* Load boot record */
+        return 3;
+    if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)                /* Check record signature (always placed at offset 510 even if the sector size is >512) */
+        return 2;
+
+    if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146)    /* Check "FAT" string */
+        return 0;
+    if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
+        return 0;
+
+    return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file system object is valid or not                       */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT chk_mounted (    /* FR_OK(0): successful, !=0: any error occurred */
+    const TCHAR **path,    /* Pointer to pointer to the path name (drive number) */
+    FATFS **rfs,        /* Pointer to pointer to the found file system object */
+    BYTE chk_wp            /* !=0: Check media write protection for write access */
+)
+{
+    BYTE fmt, b, *tbl;
+    UINT vol;
+    DSTATUS stat;
+    DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
+    WORD nrsv;
+    const TCHAR *p = *path;
+    FATFS *fs;
+
+    /* Get logical drive number from the path name */
+    vol = p[0] - '0';                    /* Is there a drive number? */
+    if (vol <= 9 && p[1] == ':') {        /* Found a drive number, get and strip it */
+        p += 2; *path = p;                /* Return pointer to the path name */
+    } else {                            /* No drive number is given */
+#if _FS_RPATH
+        vol = CurrVol;                    /* Use current drive */
+#else
+        vol = 0;                        /* Use drive 0 */
+#endif
+    }
+
+    /* Check if the logical drive is valid or not */
+    if (vol >= _VOLUMES)                 /* Is the drive number valid? */
+        return FR_INVALID_DRIVE;
+    *rfs = fs = FatFs[vol];                /* Return pointer to the corresponding file system object */
+    if (!fs) return FR_NOT_ENABLED;        /* Is the file system object available? */
+
+    ENTER_FF(fs);                        /* Lock file system */
+
+    if (fs->fs_type) {                        /* If the logical drive has been mounted */
+        stat = disk_status(fs->drv);
+        if (!(stat & STA_NOINIT)) {        /* and the physical drive is kept initialized (has not been changed), */
+#if !_FS_READONLY
+            if (chk_wp && (stat & STA_PROTECT))    /* Check write protection if needed */
+                return FR_WRITE_PROTECTED;
+#endif
+            return FR_OK;                    /* The file system object is valid */
+        }
+    }
+
+    /* The logical drive must be mounted. */
+    /* Following code attempts to mount a volume. (analyze BPB and initialize the fs object) */
+
+    fs->fs_type = 0;                    /* Clear the file system object */
+    fs->drv = (BYTE)LD2PD(vol);            /* Bind the logical drive and a physical drive */
+    stat = disk_initialize(fs->drv);    /* Initialize low level disk I/O layer */
+    if (stat & STA_NOINIT)                /* Check if the initialization succeeded */
+        return FR_NOT_READY;            /* Failed to initialize due to no media or hard error */
+#if _MAX_SS != 512                        /* Get disk sector size (variable sector size cfg only) */
+    if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK)
+        return FR_DISK_ERR;
+#endif
+#if !_FS_READONLY
+    if (chk_wp && (stat & STA_PROTECT))    /* Check disk write protection if needed */
+        return FR_WRITE_PROTECTED;
+#endif
+    /* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */
+    fmt = check_fs(fs, bsect = 0);        /* Check sector 0 if it is a VBR */
+    if (fmt == 1) {                        /* Not an FAT-VBR, the disk may be partitioned */
+        /* Check the partition listed in top of the partition table */
+        tbl = &fs->win[MBR_Table + LD2PT(vol) * SZ_PTE];/* Partition table */
+        if (tbl[4]) {                                    /* Is the partition existing? */
+            bsect = LD_DWORD(&tbl[8]);                    /* Partition offset in LBA */
+            fmt = check_fs(fs, bsect);                    /* Check the partition */
+        }
+    }
+    if (fmt == 3) return FR_DISK_ERR;
+    if (fmt) return FR_NO_FILESYSTEM;                    /* No FAT volume is found */
+
+    /* Following code initializes the file system object */
+
+    if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs))        /* (BPB_BytsPerSec must be equal to the physical sector size) */
+        return FR_NO_FILESYSTEM;
+
+    fasize = LD_WORD(fs->win+BPB_FATSz16);                /* Number of sectors per FAT */
+    if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
+    fs->fsize = fasize;
+
+    fs->n_fats = b = fs->win[BPB_NumFATs];                /* Number of FAT copies */
+    if (b != 1 && b != 2) return FR_NO_FILESYSTEM;        /* (Must be 1 or 2) */
+    fasize *= b;                                        /* Number of sectors for FAT area */
+
+    fs->csize = b = fs->win[BPB_SecPerClus];            /* Number of sectors per cluster */
+    if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM;    /* (Must be power of 2) */
+
+    fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt);    /* Number of root directory entries */
+    if (fs->n_rootdir % (SS(fs) / SZ_DIR)) return FR_NO_FILESYSTEM;    /* (BPB_RootEntCnt must be sector aligned) */
+
+    tsect = LD_WORD(fs->win+BPB_TotSec16);                /* Number of sectors on the volume */
+    if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
+
+    nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt);                /* Number of reserved sectors */
+    if (!nrsv) return FR_NO_FILESYSTEM;                    /* (BPB_RsvdSecCnt must not be 0) */
+
+    /* Determine the FAT sub type */
+    sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR);    /* RSV+FAT+DIR */
+    if (tsect < sysect) return FR_NO_FILESYSTEM;        /* (Invalid volume size) */
+    nclst = (tsect - sysect) / fs->csize;                /* Number of clusters */
+    if (!nclst) return FR_NO_FILESYSTEM;                /* (Invalid volume size) */
+    fmt = FS_FAT12;
+    if (nclst >= MIN_FAT16) fmt = FS_FAT16;
+    if (nclst >= MIN_FAT32) fmt = FS_FAT32;
+
+    /* Boundaries and Limits */
+    fs->n_fatent = nclst + 2;                            /* Number of FAT entries */
+    fs->database = bsect + sysect;                        /* Data start sector */
+    fs->fatbase = bsect + nrsv;                         /* FAT start sector */
+    if (fmt == FS_FAT32) {
+        if (fs->n_rootdir) return FR_NO_FILESYSTEM;        /* (BPB_RootEntCnt must be 0) */
+        fs->dirbase = LD_DWORD(fs->win+BPB_RootClus);    /* Root directory start cluster */
+        szbfat = fs->n_fatent * 4;                        /* (Required FAT size) */
+    } else {
+        if (!fs->n_rootdir)    return FR_NO_FILESYSTEM;    /* (BPB_RootEntCnt must not be 0) */
+        fs->dirbase = fs->fatbase + fasize;                /* Root directory start sector */
+        szbfat = (fmt == FS_FAT16) ?                    /* (Required FAT size) */
+            fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
+    }
+    if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))    /* (BPB_FATSz must not be less than required) */
+        return FR_NO_FILESYSTEM;
+
+#if !_FS_READONLY
+    /* Initialize cluster allocation information */
+    fs->free_clust = 0xFFFFFFFF;
+    fs->last_clust = 0;
+
+    /* Get fsinfo if available */
+    if (fmt == FS_FAT32) {
+         fs->fsi_flag = 0;
+        fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
+        if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK &&
+            LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
+            LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
+            LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
+                fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
+                fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
+        }
+    }
+#endif
+    fs->fs_type = fmt;        /* FAT sub-type */
+    fs->id = ++Fsid;        /* File system mount ID */
+    fs->winsect = 0;        /* Invalidate sector cache */
+    fs->wflag = 0;
+#if _FS_RPATH
+    fs->cdir = 0;            /* Current directory (root dir) */
+#endif
+#if _FS_SHARE                /* Clear file lock semaphores */
+    clear_lock(fs);
+#endif
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file/dir object is valid or not                          */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT validate (        /* FR_OK(0): The object is valid, !=0: Invalid */
+    FATFS *fs,        /* Pointer to the file system object */
+    WORD id                /* Member id of the target object to be checked */
+)
+{
+    if (!fs || !fs->fs_type || fs->id != id)
+        return FR_INVALID_OBJECT;
+
+    ENTER_FF(fs);        /* Lock file system */
+
+    if (disk_status(fs->drv) & STA_NOINIT)
+        return FR_NOT_READY;
+
+    return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Logical Drive                                         */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mount (
+    BYTE vol,        /* Logical drive number to be mounted/unmounted */
+    FATFS *fs        /* Pointer to new file system object (NULL for unmount)*/
+)
+{
+    FATFS *rfs;
+
+
+    if (vol >= _VOLUMES)            /* Check if the drive number is valid */
+        return FR_INVALID_DRIVE;
+    rfs = FatFs[vol];                /* Get current fs object */
+
+    if (rfs) {
+#if _FS_SHARE
+        clear_lock(rfs);
+#endif
+#if _FS_REENTRANT                    /* Discard sync object of the current volume */
+        if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
+#endif
+        rfs->fs_type = 0;            /* Clear old fs object */
+    }
+
+    if (fs) {
+        fs->fs_type = 0;            /* Clear new fs object */
+#if _FS_REENTRANT                    /* Create sync object for the new volume */
+        if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
+#endif
+    }
+    FatFs[vol] = fs;                /* Register new fs object */
+
+    return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_open (
+    FIL_t *fp,            /* Pointer to the blank file object */
+    const TCHAR *path,    /* Pointer to the file name */
+    BYTE mode            /* Access mode and file open mode flags */
+)
+{
+    FRESULT res;
+    DIR_t dj;
+    BYTE *dir;
+    DEF_NAMEBUF;
+
+
+    fp->fs = 0;            /* Clear file object */
+
+#if !_FS_READONLY
+    mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
+    res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ));
+#else
+    mode &= FA_READ;
+    res = chk_mounted(&path, &dj.fs, 0);
+#endif
+    INIT_BUF(dj);
+    if (res == FR_OK)
+        res = follow_path(&dj, path);    /* Follow the file path */
+    dir = dj.dir;
+
+#if !_FS_READONLY    /* R/W configuration */
+    if (res == FR_OK) {
+        if (!dir)    /* Current dir itself */
+            res = FR_INVALID_NAME;
+#if _FS_SHARE
+        else
+            res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+#endif
+    }
+    /* Create or Open a file */
+    if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) {
+        DWORD dw, cl;
+
+        if (res != FR_OK) {        /* No file, create new */
+            if (res == FR_NO_FILE)            /* There is no file to open, create a new entry */
+#if _FS_SHARE
+                res = enq_lock(dj.fs) ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
+#else
+                res = dir_register(&dj);
+#endif
+            mode |= FA_CREATE_ALWAYS;        /* File is created */
+            dir = dj.dir;                    /* New entry */
+        }
+        else {                    /* Any object is already existing */
+            if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) {    /* Cannot overwrite it (R/O or DIR) */
+                res = FR_DENIED;
+            } else {
+                if (mode & FA_CREATE_NEW)    /* Cannot create as new file */
+                    res = FR_EXIST;
+            }
+        }
+        if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) {    /* Truncate it if overwrite mode */
+            dw = get_fattime();                    /* Created time */
+            ST_DWORD(dir+DIR_CrtTime, dw);
+            dir[DIR_Attr] = 0;                    /* Reset attribute */
+            ST_DWORD(dir+DIR_FileSize, 0);        /* size = 0 */
+            cl = LD_CLUST(dir);                    /* Get start cluster */
+            ST_CLUST(dir, 0);                    /* cluster = 0 */
+            dj.fs->wflag = 1;
+            if (cl) {                            /* Remove the cluster chain if exist */
+                dw = dj.fs->winsect;
+                res = remove_chain(dj.fs, cl);
+                if (res == FR_OK) {
+                    dj.fs->last_clust = cl - 1;    /* Reuse the cluster hole */
+                    res = move_window(dj.fs, dw);
+        }
+    }
+        }
+    }
+    else {    /* Open an existing file */
+        if (res == FR_OK) {                        /* Follow succeeded */
+            if (dir[DIR_Attr] & AM_DIR) {        /* It is a directory */
+                res = FR_NO_FILE;
+            } else {
+        if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+                    res = FR_DENIED;
+            }
+    }
+    }
+    if (res == FR_OK) {
+        if (mode & FA_CREATE_ALWAYS)            /* Set file change flag if created or overwritten */
+            mode |= FA__WRITTEN;
+    fp->dir_sect = dj.fs->winsect;        /* Pointer to the directory entry */
+    fp->dir_ptr = dir;
+#if _FS_SHARE
+        fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
+        if (!fp->lockid) res = FR_INT_ERR;
+#endif
+    }
+
+#else                /* R/O configuration */
+    if (res == FR_OK) {                    /* Follow succeeded */
+        if (!dir) {                        /* Current dir itself */
+            res = FR_INVALID_NAME;
+        } else {
+            if (dir[DIR_Attr] & AM_DIR)    /* It is a directory */
+                res = FR_NO_FILE;
+        }
+    }
+#endif
+    FREE_BUF();
+
+    if (res == FR_OK) {
+    fp->flag = mode;                    /* File access mode */
+        fp->sclust = LD_CLUST(dir);            /* File start cluster */
+        fp->fsize = LD_DWORD(dir+DIR_FileSize);    /* File size */
+        fp->fptr = 0;                        /* File pointer */
+        fp->dsect = 0;
+#if _USE_FASTSEEK
+        fp->cltbl = 0;                        /* Normal seek mode */
+#endif
+        fp->fs = dj.fs; fp->id = dj.fs->id;    /* Validate file object */
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File                                                             */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_read (
+    FIL_t *fp,         /* Pointer to the file object */
+    void *buff,        /* Pointer to data buffer */
+    UINT btr,        /* Number of bytes to read */
+    UINT *br        /* Pointer to number of bytes read */
+)
+{
+    FRESULT res;
+    DWORD clst, sect, remain;
+    UINT rcnt, cc;
+    BYTE csect, *rbuff = (BYTE*)buff;
+
+
+    *br = 0;    /* Initialize byte counter */
+
+    res = validate(fp->fs, fp->id);                /* Check validity */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)                    /* Aborted file? */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_READ))                     /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+    remain = fp->fsize - fp->fptr;
+    if (btr > remain) btr = (UINT)remain;            /* Truncate btr by remaining bytes */
+
+    for ( ;  btr;                                /* Repeat until all data read */
+        rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+        if ((fp->fptr % SS(fp->fs)) == 0) {            /* On the sector boundary? */
+            csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));    /* Sector offset in the cluster */
+            if (!csect) {                        /* On the cluster boundary? */
+                if (fp->fptr == 0) {            /* On the top of the file? */
+                    clst = fp->sclust;            /* Follow from the origin */
+                } else {                        /* Middle or end of the file */
+#if _USE_FASTSEEK
+                    if (fp->cltbl)
+                        clst = clmt_clust(fp, fp->fptr);    /* Get cluster# from the CLMT */
+                    else
+#endif
+                        clst = get_fat(fp->fs, fp->clust);    /* Follow cluster chain on the FAT */
+                }
+                if (clst < 2) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->clust = clst;                /* Update current cluster */
+            }
+            sect = clust2sect(fp->fs, fp->clust);    /* Get current sector */
+            if (!sect) ABORT(fp->fs, FR_INT_ERR);
+            sect += csect;
+            cc = btr / SS(fp->fs);                    /* When remaining bytes >= sector size, */
+            if (cc) {                                /* Read maximum contiguous sectors directly */
+                if (csect + cc > fp->fs->csize)    /* Clip at cluster boundary */
+                    cc = fp->fs->csize - csect;
+                if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+#if !_FS_READONLY && _FS_MINIMIZE <= 2            /* Replace one of the read sectors with cached data if it contains a dirty sector */
+#if _FS_TINY
+                if (fp->fs->wflag && fp->fs->winsect - sect < cc)
+                    mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
+#else
+                if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
+                    mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
+#endif
+#endif
+                rcnt = SS(fp->fs) * cc;                /* Number of bytes transferred */
+                continue;
+            }
+#if !_FS_TINY
+            if (fp->dsect != sect) {            /* Load data sector if not in cache */
+#if !_FS_READONLY
+                if (fp->flag & FA__DIRTY) {        /* Write-back dirty sector cache */
+                    if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                        ABORT(fp->fs, FR_DISK_ERR);
+                    fp->flag &= ~FA__DIRTY;
+                }
+#endif
+                if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)    /* Fill sector cache */
+                    ABORT(fp->fs, FR_DISK_ERR);
+            }
+#endif
+            fp->dsect = sect;
+        }
+        rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));    /* Get partial sector data from sector buffer */
+        if (rcnt > btr) rcnt = btr;
+#if _FS_TINY
+        if (move_window(fp->fs, fp->dsect))        /* Move sector window */
+            ABORT(fp->fs, FR_DISK_ERR);
+        mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt);    /* Pick partial sector */
+#else
+        mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt);    /* Pick partial sector */
+#endif
+    }
+
+    LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Write File                                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_write (
+    FIL_t *fp,            /* Pointer to the file object */
+    const void *buff,    /* Pointer to the data to be written */
+    UINT btw,            /* Number of bytes to write */
+    UINT *bw            /* Pointer to number of bytes written */
+)
+{
+    FRESULT res;
+    DWORD clst, sect;
+    UINT wcnt, cc;
+    const BYTE *wbuff = (BYTE*)buff;
+    BYTE csect;
+
+
+    *bw = 0;    /* Initialize byte counter */
+
+    res = validate(fp->fs, fp->id);            /* Check validity */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)                /* Aborted file? */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_WRITE))                /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+    if ((DWORD)(fp->fsize + btw) < fp->fsize) btw = 0;    /* File size cannot reach 4GB */
+
+    for ( ;  btw;                            /* Repeat until all data written */
+        wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+        if ((fp->fptr % SS(fp->fs)) == 0) {            /* On the sector boundary? */
+            csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));    /* Sector offset in the cluster */
+            if (!csect) {                    /* On the cluster boundary? */
+                if (fp->fptr == 0) {                /* On the top of the file? */
+                    clst = fp->sclust;        /* Follow from the origin */
+                    if (clst == 0)            /* When no cluster is allocated, */
+                        fp->sclust = clst = create_chain(fp->fs, 0);    /* Create a new cluster chain */
+                } else {                            /* Middle or end of the file */
+#if _USE_FASTSEEK
+                    if (fp->cltbl)
+                        clst = clmt_clust(fp, fp->fptr);    /* Get cluster# from the CLMT */
+                    else
+#endif
+                        clst = create_chain(fp->fs, fp->clust);    /* Follow or stretch cluster chain on the FAT */
+                }
+                if (clst == 0) break;        /* Could not allocate a new cluster (disk full) */
+                if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->clust = clst;            /* Update current cluster */
+                }
+#if _FS_TINY
+            if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0))    /* Write-back sector cache */
+                ABORT(fp->fs, FR_DISK_ERR);
+#else
+            if (fp->flag & FA__DIRTY) {        /* Write-back sector cache */
+                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+                fp->flag &= ~FA__DIRTY;
+            }
+#endif
+            sect = clust2sect(fp->fs, fp->clust);    /* Get current sector */
+            if (!sect) ABORT(fp->fs, FR_INT_ERR);
+            sect += csect;
+            cc = btw / SS(fp->fs);                    /* When remaining bytes >= sector size, */
+            if (cc) {                                /* Write maximum contiguous sectors directly */
+                if (csect + cc > fp->fs->csize)    /* Clip at cluster boundary */
+                    cc = fp->fs->csize - csect;
+                if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+#if _FS_TINY
+                if (fp->fs->winsect - sect < cc) {    /* Refill sector cache if it gets invalidated by the direct write */
+                    mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
+                    fp->fs->wflag = 0;
+                }
+#else
+                if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
+                    mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
+                    fp->flag &= ~FA__DIRTY;
+                }
+#endif
+                wcnt = SS(fp->fs) * cc;                /* Number of bytes transferred */
+                continue;
+            }
+#if _FS_TINY
+            if (fp->fptr >= fp->fsize) {    /* Avoid silly cache filling at growing edge */
+                if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
+                fp->fs->winsect = sect;
+                }
+#else
+            if (fp->dsect != sect) {        /* Fill sector cache with file data */
+                if (fp->fptr < fp->fsize &&
+                    disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
+                        ABORT(fp->fs, FR_DISK_ERR);
+            }
+#endif
+            fp->dsect = sect;
+        }
+        wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));    /* Put partial sector into file I/O buffer */
+        if (wcnt > btw) wcnt = btw;
+#if _FS_TINY
+        if (move_window(fp->fs, fp->dsect))    /* Move sector window */
+            ABORT(fp->fs, FR_DISK_ERR);
+        mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt);    /* Fit partial sector */
+        fp->fs->wflag = 1;
+#else
+        mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt);    /* Fit partial sector */
+        fp->flag |= FA__DIRTY;
+#endif
+    }
+
+    if (fp->fptr > fp->fsize) fp->fsize = fp->fptr;    /* Update file size if needed */
+    fp->flag |= FA__WRITTEN;                        /* Set file change flag */
+
+    LEAVE_FF(fp->fs, FR_OK);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize the File Object                                           */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_sync (
+    FIL_t *fp        /* Pointer to the file object */
+)
+{
+    FRESULT res;
+    DWORD tim;
+    BYTE *dir;
+
+
+    res = validate(fp->fs, fp->id);        /* Check validity of the object */
+    if (res == FR_OK) {
+        if (fp->flag & FA__WRITTEN) {    /* Has the file been written? */
+#if !_FS_TINY    /* Write-back dirty buffer */
+            if (fp->flag & FA__DIRTY) {
+                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                    LEAVE_FF(fp->fs, FR_DISK_ERR);
+                fp->flag &= ~FA__DIRTY;
+            }
+#endif
+            /* Update the directory entry */
+            res = move_window(fp->fs, fp->dir_sect);
+            if (res == FR_OK) {
+            dir = fp->dir_ptr;
+            dir[DIR_Attr] |= AM_ARC;                        /* Set archive bit */
+                ST_DWORD(dir+DIR_FileSize, fp->fsize);        /* Update file size */
+                ST_CLUST(dir, fp->sclust);                    /* Update start cluster */
+                tim = get_fattime();                        /* Update updated time */
+                ST_DWORD(dir+DIR_WrtTime, tim);
+                fp->flag &= ~FA__WRITTEN;
+                fp->fs->wflag = 1;
+            res = sync(fp->fs);
+        }
+    }
+    }
+
+    LEAVE_FF(fp->fs, res);
+}
+
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close File                                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_close (
+    FIL_t *fp        /* Pointer to the file object to be closed */
+)
+{
+    FRESULT res;
+
+#if _FS_READONLY
+    FATFS *fs = fp->fs;
+    res = validate(fs, fp->id);
+    if (res == FR_OK) fp->fs = 0;    /* Discard file object */
+    LEAVE_FF(fs, res);
+
+#else
+    res = f_sync(fp);        /* Flush cached data */
+#if _FS_SHARE
+    if (res == FR_OK) {        /* Decrement open counter */
+#if _FS_REENTRANT
+    res = validate(fp->fs, fp->id);
+        if (res == FR_OK) {
+            res = dec_lock(fp->lockid);    
+            unlock_fs(fp->fs, FR_OK);
+        }
+#else
+        res = dec_lock(fp->lockid);
+#endif
+    }
+#endif
+    if (res == FR_OK) fp->fs = 0;    /* Discard file object */
+    return res;
+#endif
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Current Drive/Directory Handlings                                     */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_RPATH >= 1
+
+FRESULT f_chdrive (
+    BYTE drv        /* Drive number */
+)
+{
+    if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+
+    CurrVol = drv;
+
+    return FR_OK;
+}
+
+
+
+FRESULT f_chdir (
+    const TCHAR *path    /* Pointer to the directory path */
+)
+{
+    FRESULT res;
+    DIR_t dj;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 0);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);        /* Follow the path */
+        FREE_BUF();
+        if (res == FR_OK) {                    /* Follow completed */
+            if (!dj.dir) {
+                dj.fs->cdir = dj.sclust;    /* Start directory itself */
+            } else {
+                if (dj.dir[DIR_Attr] & AM_DIR)    /* Reached to the directory */
+                    dj.fs->cdir = LD_CLUST(dj.dir);
+                else
+                    res = FR_NO_PATH;        /* Reached but a file */
+            }
+        }
+        if (res == FR_NO_FILE) res = FR_NO_PATH;
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+#if _FS_RPATH >= 2
+FRESULT f_getcwd (
+    TCHAR *path,    /* Pointer to the directory path */
+    UINT sz_path    /* Size of path */
+)
+{
+    FRESULT res;
+    DIR_t dj;
+    UINT i, n;
+    DWORD ccl;
+    TCHAR *tp;
+    FILINFO fno;
+    DEF_NAMEBUF;
+
+
+    *path = 0;
+    res = chk_mounted((const TCHAR**)&path, &dj.fs, 0);    /* Get current volume */
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        i = sz_path;        /* Bottom of buffer (dir stack base) */
+        dj.sclust = dj.fs->cdir;            /* Start to follow upper dir from current dir */
+        while ((ccl = dj.sclust) != 0) {    /* Repeat while current dir is a sub-dir */
+            res = dir_sdi(&dj, 1);            /* Get parent dir */
+            if (res != FR_OK) break;
+            res = dir_read(&dj);
+            if (res != FR_OK) break;
+            dj.sclust = LD_CLUST(dj.dir);    /* Goto parent dir */
+            res = dir_sdi(&dj, 0);
+            if (res != FR_OK) break;
+            do {                            /* Find the entry links to the child dir */
+                res = dir_read(&dj);
+                if (res != FR_OK) break;
+                if (ccl == LD_CLUST(dj.dir)) break;    /* Found the entry */
+                res = dir_next(&dj, 0);    
+            } while (res == FR_OK);
+            if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
+            if (res != FR_OK) break;
+#if _USE_LFN
+            fno.lfname = path;
+            fno.lfsize = i;
+#endif
+            get_fileinfo(&dj, &fno);        /* Get the dir name and push it to the buffer */
+            tp = fno.fname;
+            if (_USE_LFN && *path) tp = path;
+            for (n = 0; tp[n]; n++) ;
+            if (i < n + 3) {
+                res = FR_NOT_ENOUGH_CORE; break;
+            }
+            while (n) path[--i] = tp[--n];
+            path[--i] = '/';
+        }
+        tp = path;
+        if (res == FR_OK) {
+            *tp++ = '0' + CurrVol;            /* Put drive number */
+            *tp++ = ':';
+            if (i == sz_path) {                /* Root-dir */
+                *tp++ = '/';
+            } else {                        /* Sub-dir */
+                do        /* Add stacked path str */
+                    *tp++ = path[i++];
+                while (i < sz_path);
+            }
+        }
+        *tp = 0;
+        FREE_BUF();
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+#endif /* _FS_RPATH >= 2 */
+#endif /* _FS_RPATH >= 1 */
+
+
+
+#if _FS_MINIMIZE <= 2
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_lseek (
+    FIL_t *fp,        /* Pointer to the file object */
+    DWORD ofs        /* File pointer from top of file */
+)
+{
+    FRESULT res;
+
+
+    res = validate(fp->fs, fp->id);        /* Check validity of the object */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)            /* Check abort flag */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+
+#if _USE_FASTSEEK
+    if (fp->cltbl) {    /* Fast seek */
+        DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
+
+        if (ofs == CREATE_LINKMAP) {    /* Create CLMT */
+            tbl = fp->cltbl;
+            tlen = *tbl++; ulen = 2;    /* Given table size and required table size */
+            cl = fp->sclust;            /* Top of the chain */
+            if (cl) {
+                do {
+                    /* Get a fragment */
+                    tcl = cl; ncl = 0; ulen += 2;    /* Top, length and used items */
+                    do {
+                        pcl = cl; ncl++;
+                        cl = get_fat(fp->fs, cl);
+                        if (cl <= 1) ABORT(fp->fs, FR_INT_ERR);
+                        if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                    } while (cl == pcl + 1);
+                    if (ulen <= tlen) {        /* Store the length and top of the fragment */
+                        *tbl++ = ncl; *tbl++ = tcl;
+                    }
+                } while (cl < fp->fs->n_fatent);    /* Repeat until end of chain */
+            }
+            *fp->cltbl = ulen;    /* Number of items used */
+            if (ulen <= tlen)
+                *tbl = 0;        /* Terminate table */
+            else
+                res = FR_NOT_ENOUGH_CORE;    /* Given table size is smaller than required */
+
+        } else {                        /* Fast seek */
+            if (ofs > fp->fsize)        /* Clip offset at the file size */
+                ofs = fp->fsize;
+            fp->fptr = ofs;                /* Set file pointer */
+            if (ofs) {
+                fp->clust = clmt_clust(fp, ofs - 1);
+                dsc = clust2sect(fp->fs, fp->clust);
+                if (!dsc) ABORT(fp->fs, FR_INT_ERR);
+                dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1);
+                if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) {    /* Refill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+                    if (fp->flag & FA__DIRTY) {        /* Write-back dirty sector cache */
+                        if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                            ABORT(fp->fs, FR_DISK_ERR);
+                        fp->flag &= ~FA__DIRTY;
+                    }
+#endif
+                    if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK)    /* Load current sector */
+                        ABORT(fp->fs, FR_DISK_ERR);
+#endif
+                    fp->dsect = dsc;
+                }
+            }
+        }
+    } else
+#endif
+
+    /* Normal Seek */
+    {
+        DWORD clst, bcs, nsect, ifptr;
+
+    if (ofs > fp->fsize                    /* In read-only mode, clip offset with the file size */
+#if !_FS_READONLY
+         && !(fp->flag & FA_WRITE)
+#endif
+        ) ofs = fp->fsize;
+
+    ifptr = fp->fptr;
+        fp->fptr = nsect = 0;
+        if (ofs) {
+            bcs = (DWORD)fp->fs->csize * SS(fp->fs);    /* Cluster size (byte) */
+        if (ifptr > 0 &&
+                (ofs - 1) / bcs >= (ifptr - 1) / bcs) {    /* When seek to same or following cluster, */
+                fp->fptr = (ifptr - 1) & ~(bcs - 1);    /* start from the current cluster */
+            ofs -= fp->fptr;
+                clst = fp->clust;
+        } else {                                    /* When seek to back cluster, */
+                clst = fp->sclust;                        /* start from the first cluster */
+#if !_FS_READONLY
+                if (clst == 0) {                        /* If no cluster chain, create a new chain */
+                    clst = create_chain(fp->fs, 0);
+                    if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
+                    if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                    fp->sclust = clst;
+            }
+#endif
+                fp->clust = clst;
+        }
+            if (clst != 0) {
+                while (ofs > bcs) {                        /* Cluster following loop */
+#if !_FS_READONLY
+                if (fp->flag & FA_WRITE) {            /* Check if in write mode or not */
+                        clst = create_chain(fp->fs, clst);    /* Force stretch if in write mode */
+                        if (clst == 0) {                /* When disk gets full, clip file size */
+                            ofs = bcs; break;
+                    }
+                } else
+#endif
+                        clst = get_fat(fp->fs, clst);    /* Follow cluster chain if not in write mode */
+                    if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                    if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR);
+                    fp->clust = clst;
+                    fp->fptr += bcs;
+                    ofs -= bcs;
+            }
+            fp->fptr += ofs;
+                if (ofs % SS(fp->fs)) {
+                    nsect = clust2sect(fp->fs, clst);    /* Current sector */
+                    if (!nsect) ABORT(fp->fs, FR_INT_ERR);
+                    nsect += ofs / SS(fp->fs);
+            }
+        }
+    }
+        if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {    /* Fill sector cache if needed */
+#if !_FS_TINY
+#if !_FS_READONLY
+            if (fp->flag & FA__DIRTY) {            /* Write-back dirty sector cache */
+                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
+                    ABORT(fp->fs, FR_DISK_ERR);
+                fp->flag &= ~FA__DIRTY;
+        }
+#endif
+            if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK)    /* Fill sector cache */
+                ABORT(fp->fs, FR_DISK_ERR);
+#endif
+            fp->dsect = nsect;
+    }
+#if !_FS_READONLY
+        if (fp->fptr > fp->fsize) {            /* Set file change flag if the file size is extended */
+        fp->fsize = fp->fptr;
+        fp->flag |= FA__WRITTEN;
+    }
+#endif
+}
+
+    LEAVE_FF(fp->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE <= 1
+/*-----------------------------------------------------------------------*/
+/* Create a Directroy Object                                             */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_opendir (
+    DIR_t *dj,            /* Pointer to directory object to create */
+    const TCHAR *path    /* Pointer to the directory path */
+)
+{
+    FRESULT res;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj->fs, 0);
+    if (res == FR_OK) {
+        INIT_BUF(*dj);
+        res = follow_path(dj, path);            /* Follow the path to the directory */
+        FREE_BUF();
+        if (res == FR_OK) {                        /* Follow completed */
+            if (dj->dir) {                        /* It is not the root dir */
+                if (dj->dir[DIR_Attr] & AM_DIR) {    /* The object is a directory */
+                    dj->sclust = LD_CLUST(dj->dir);
+                } else {                        /* The object is not a directory */
+                    res = FR_NO_PATH;
+                }
+            }
+            if (res == FR_OK) {
+            dj->id = dj->fs->id;
+                res = dir_sdi(dj, 0);            /* Rewind dir */
+            }
+        }
+        if (res == FR_NO_FILE) res = FR_NO_PATH;
+    }
+
+    LEAVE_FF(dj->fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequense                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_readdir (
+    DIR_t *dj,            /* Pointer to the open directory object */
+    FILINFO *fno        /* Pointer to file information to return */
+)
+{
+    FRESULT res;
+    DEF_NAMEBUF;
+
+    res = validate(dj->fs, dj->id);            /* Check validity of the object */
+    if (res == FR_OK) {
+        if (!fno) {
+            res = dir_sdi(dj, 0);            /* Rewind the directory object */
+        } else {
+            INIT_BUF(*dj);
+            res = dir_read(dj);                /* Read an directory item */
+            if (res == FR_NO_FILE) {        /* Reached end of dir */
+                dj->sect = 0;
+                res = FR_OK;
+            }
+            if (res == FR_OK) {                /* A valid entry is found */
+                get_fileinfo(dj, fno);        /* Get the object information */
+                res = dir_next(dj, 0);        /* Increment index for next */
+                if (res == FR_NO_FILE) {
+                    dj->sect = 0;
+                    res = FR_OK;
+                }
+            }
+            FREE_BUF();
+        }
+    }
+
+    LEAVE_FF(dj->fs, res);
+}
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status                                                       */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+    const TCHAR *path,    /* Pointer to the file path */
+    FILINFO *fno        /* Pointer to file information to return */
+)
+{
+    FRESULT res;
+    DIR_t dj;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 0);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);    /* Follow the file path */
+        if (res == FR_OK) {                /* Follow completed */
+            if (dj.dir)        /* Found an object */
+                get_fileinfo(&dj, fno);
+            else        /* It is root dir */
+                res = FR_INVALID_NAME;
+        }
+        FREE_BUF();
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters                                           */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+    const TCHAR *path,    /* Pointer to the logical drive number (root dir) */
+    DWORD *nclst,        /* Pointer to the variable to return number of free clusters */
+    FATFS **fatfs        /* Pointer to pointer to corresponding file system object to return */
+)
+{
+    FRESULT res;
+    DWORD n, clst, sect, stat;
+    UINT i;
+    BYTE fat, *p;
+
+
+    /* Get drive number */
+    res = chk_mounted(&path, fatfs, 0);
+    if (res == FR_OK) {
+        /* If free_clust is valid, return it without full cluster scan */
+        if ((*fatfs)->free_clust <= (*fatfs)->n_fatent - 2) {
+            *nclst = (*fatfs)->free_clust;
+        } else {
+    /* Get number of free clusters */
+    fat = (*fatfs)->fs_type;
+    n = 0;
+    if (fat == FS_FAT12) {
+                clst = 2;
+        do {
+                    stat = get_fat(*fatfs, clst);
+                    if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
+                    if (stat == 1) { res = FR_INT_ERR; break; }
+                    if (stat == 0) n++;
+                } while (++clst < (*fatfs)->n_fatent);
+    } else {
+                clst = (*fatfs)->n_fatent;
+        sect = (*fatfs)->fatbase;
+                i = 0; p = 0;
+        do {
+                    if (!i) {
+                        res = move_window(*fatfs, sect++);
+                        if (res != FR_OK) break;
+                p = (*fatfs)->win;
+                        i = SS(*fatfs);
+            }
+            if (fat == FS_FAT16) {
+                if (LD_WORD(p) == 0) n++;
+                        p += 2; i -= 2;
+            } else {
+                        if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
+                        p += 4; i -= 4;
+            }
+                } while (--clst);
+    }
+    (*fatfs)->free_clust = n;
+    if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
+            *nclst = n;
+        }
+    }
+    LEAVE_FF(*fatfs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Truncate File                                                         */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_truncate (
+    FIL_t *fp        /* Pointer to the file object */
+)
+{
+    FRESULT res;
+    DWORD ncl;
+
+
+    res = validate(fp->fs, fp->id);        /* Check validity of the object */
+    if (res == FR_OK) {
+        if (fp->flag & FA__ERROR) {            /* Check abort flag */
+            res = FR_INT_ERR;
+        } else {
+            if (!(fp->flag & FA_WRITE))        /* Check access mode */
+                res = FR_DENIED;
+        }
+    }
+    if (res == FR_OK) {
+        if (fp->fsize > fp->fptr) {
+            fp->fsize = fp->fptr;    /* Set file size to current R/W point */
+            fp->flag |= FA__WRITTEN;
+            if (fp->fptr == 0) {    /* When set file size to zero, remove entire cluster chain */
+                res = remove_chain(fp->fs, fp->sclust);
+                fp->sclust = 0;
+            } else {                /* When truncate a part of the file, remove remaining clusters */
+                ncl = get_fat(fp->fs, fp->clust);
+                res = FR_OK;
+                if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
+                if (ncl == 1) res = FR_INT_ERR;
+                if (res == FR_OK && ncl < fp->fs->n_fatent) {
+                    res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF);
+                    if (res == FR_OK) res = remove_chain(fp->fs, ncl);
+                }
+            }
+        }
+        if (res != FR_OK) fp->flag |= FA__ERROR;
+    }
+
+    LEAVE_FF(fp->fs, res);
+    }
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Delete a File or Directory                                            */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_unlink (
+    const TCHAR *path        /* Pointer to the file or directory path */
+)
+{
+    FRESULT res;
+    DIR_t dj, sdj;
+    BYTE *dir;
+    DWORD dclst;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);        /* Follow the file path */
+        if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;            /* Cannot remove dot entry */
+#if _FS_SHARE
+        if (res == FR_OK) res = chk_lock(&dj, 2);    /* Cannot remove open file */
+#endif
+        if (res == FR_OK) {                    /* The object is accessible */
+            dir = dj.dir;
+            if (!dir) {
+                res = FR_INVALID_NAME;        /* Cannot remove the start directory */
+            } else {
+                if (dir[DIR_Attr] & AM_RDO)
+                    res = FR_DENIED;        /* Cannot remove R/O object */
+            }
+            dclst = LD_CLUST(dir);
+            if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) {    /* Is it a sub-dir? */
+                if (dclst < 2) {
+                    res = FR_INT_ERR;
+                } else {
+                    mem_cpy(&sdj, &dj, sizeof(DIR_t));    /* Check if the sub-dir is empty or not */
+                    sdj.sclust = dclst;
+                    res = dir_sdi(&sdj, 2);        /* Exclude dot entries */
+                    if (res == FR_OK) {
+                        res = dir_read(&sdj);
+                        if (res == FR_OK            /* Not empty dir */
+#if _FS_RPATH
+                        || dclst == sdj.fs->cdir    /* Current dir */
+#endif
+                        ) res = FR_DENIED;
+                        if (res == FR_NO_FILE) res = FR_OK;    /* Empty */
+                    }
+                }
+            }
+            if (res == FR_OK) {
+                res = dir_remove(&dj);        /* Remove the directory entry */
+                if (res == FR_OK) {
+                    if (dclst)                /* Remove the cluster chain if exist */
+                        res = remove_chain(dj.fs, dclst);
+                    if (res == FR_OK) res = sync(dj.fs);
+                }
+            }
+        }
+        FREE_BUF();
+    }
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory                                                    */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+    const TCHAR *path        /* Pointer to the directory path */
+)
+{
+    FRESULT res;
+    DIR_t dj;
+    BYTE *dir, n;
+    DWORD dsc, dcl, pcl, tim = get_fattime();
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);            /* Follow the file path */
+        if (res == FR_OK) res = FR_EXIST;        /* Any object with same name is already existing */
+        if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+        if (res == FR_NO_FILE) {                /* Can create a new directory */
+            dcl = create_chain(dj.fs, 0);        /* Allocate a cluster for the new directory table */
+            res = FR_OK;
+            if (dcl == 0) res = FR_DENIED;        /* No space to allocate a new cluster */
+            if (dcl == 1) res = FR_INT_ERR;
+            if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR;
+            if (res == FR_OK)                    /* Flush FAT */
+                res = move_window(dj.fs, 0);
+            if (res == FR_OK) {                    /* Initialize the new directory table */
+                dsc = clust2sect(dj.fs, dcl);
+                dir = dj.fs->win;
+                mem_set(dir, 0, SS(dj.fs));
+                mem_set(dir+DIR_Name, ' ', 8+3);    /* Create "." entry */
+                dir[DIR_Name] = '.';
+                dir[DIR_Attr] = AM_DIR;
+                ST_DWORD(dir+DIR_WrtTime, tim);
+                ST_CLUST(dir, dcl);
+                mem_cpy(dir+SZ_DIR, dir, SZ_DIR);     /* Create ".." entry */
+                dir[33] = '.'; pcl = dj.sclust;
+                if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
+                    pcl = 0;
+                ST_CLUST(dir+SZ_DIR, pcl);
+                for (n = dj.fs->csize; n; n--) {    /* Write dot entries and clear following sectors */
+                    dj.fs->winsect = dsc++;
+                    dj.fs->wflag = 1;
+                    res = move_window(dj.fs, 0);
+                    if (res != FR_OK) break;
+                    mem_set(dir, 0, SS(dj.fs));
+    }
+            }
+            if (res == FR_OK) res = dir_register(&dj);    /* Register the object to the directoy */
+            if (res != FR_OK) {
+                remove_chain(dj.fs, dcl);            /* Could not register, remove cluster chain */
+            } else {
+                dir = dj.dir;
+    dir[DIR_Attr] = AM_DIR;                        /* Attribute */
+                ST_DWORD(dir+DIR_WrtTime, tim);        /* Created time */
+                ST_CLUST(dir, dcl);                    /* Table start cluster */
+                dj.fs->wflag = 1;
+                res = sync(dj.fs);
+            }
+        }
+        FREE_BUF();
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Attribute                                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+    const TCHAR *path,    /* Pointer to the file path */
+    BYTE value,            /* Attribute bits */
+    BYTE mask            /* Attribute mask to change */
+)
+{
+    FRESULT res;
+    DIR_t dj;
+    BYTE *dir;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);        /* Follow the file path */
+        FREE_BUF();
+        if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+        if (res == FR_OK) {
+            dir = dj.dir;
+            if (!dir) {                        /* Is it a root directory? */
+                res = FR_INVALID_NAME;
+            } else {                        /* File or sub directory */
+                mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;    /* Valid attribute mask */
+                dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask);    /* Apply attribute change */
+                dj.fs->wflag = 1;
+                res = sync(dj.fs);
+            }
+        }
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change Timestamp                                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_utime (
+    const TCHAR *path,    /* Pointer to the file/directory name */
+    const FILINFO *fno    /* Pointer to the time stamp to be set */
+)
+{
+    FRESULT res;
+    DIR_t dj;
+    BYTE *dir;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path, &dj.fs, 1);
+    if (res == FR_OK) {
+        INIT_BUF(dj);
+        res = follow_path(&dj, path);    /* Follow the file path */
+        FREE_BUF();
+        if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+        if (res == FR_OK) {
+            dir = dj.dir;
+            if (!dir) {                    /* Root directory */
+                res = FR_INVALID_NAME;
+            } else {                    /* File or sub-directory */
+                ST_WORD(dir+DIR_WrtTime, fno->ftime);
+                ST_WORD(dir+DIR_WrtDate, fno->fdate);
+                dj.fs->wflag = 1;
+                res = sync(dj.fs);
+            }
+        }
+    }
+
+    LEAVE_FF(dj.fs, res);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Rename File/Directory                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_rename (
+    const TCHAR *path_old,    /* Pointer to the old name */
+    const TCHAR *path_new    /* Pointer to the new name */
+)
+{
+    FRESULT res;
+    DIR_t djo, djn;
+    BYTE buf[21], *dir;
+    DWORD dw;
+    DEF_NAMEBUF;
+
+
+    res = chk_mounted(&path_old, &djo.fs, 1);
+    if (res == FR_OK) {
+        djn.fs = djo.fs;
+        INIT_BUF(djo);
+        res = follow_path(&djo, path_old);        /* Check old object */
+        if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT))
+            res = FR_INVALID_NAME;
+#if _FS_SHARE
+        if (res == FR_OK) res = chk_lock(&djo, 2);
+#endif
+        if (res == FR_OK) {                        /* Old object is found */
+            if (!djo.dir) {                        /* Is root dir? */
+                res = FR_NO_FILE;
+            } else {
+                mem_cpy(buf, djo.dir+DIR_Attr, 21);        /* Save the object information except for name */
+                mem_cpy(&djn, &djo, sizeof(DIR_t));        /* Check new object */
+                res = follow_path(&djn, path_new);
+                if (res == FR_OK) res = FR_EXIST;        /* The new object name is already existing */
+                if (res == FR_NO_FILE) {                 /* Is it a valid path and no name collision? */
+/* Start critical section that any interruption or error can cause cross-link */
+                    res = dir_register(&djn);            /* Register the new entry */
+                    if (res == FR_OK) {
+                        dir = djn.dir;                    /* Copy object information except for name */
+                        mem_cpy(dir+13, buf+2, 19);
+                        dir[DIR_Attr] = buf[0] | AM_ARC;
+                        djo.fs->wflag = 1;
+                        if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) {        /* Update .. entry in the directory if needed */
+                            dw = clust2sect(djn.fs, LD_CLUST(dir));
+                            if (!dw) {
+                                res = FR_INT_ERR;
+                            } else {
+                                res = move_window(djn.fs, dw);
+                                dir = djn.fs->win+SZ_DIR;    /* .. entry */
+                                if (res == FR_OK && dir[1] == '.') {
+                                    dw = (djn.fs->fs_type == FS_FAT32 && djn.sclust == djn.fs->dirbase) ? 0 : djn.sclust;
+                                    ST_CLUST(dir, dw);
+                                    djn.fs->wflag = 1;
+                                }
+                            }
+                        }
+                        if (res == FR_OK) {
+                            res = dir_remove(&djo);        /* Remove old entry */
+                            if (res == FR_OK)
+                                res = sync(djo.fs);
+                        }
+                    }
+/* End critical section */
+                }
+            }
+        }
+        FREE_BUF();
+    }
+    LEAVE_FF(djo.fs, res);
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _FS_MINIMIZE == 0 */
+#endif /* _FS_MINIMIZE <= 1 */
+#endif /* _FS_MINIMIZE <= 2 */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Forward data to the stream directly (available on only tiny cfg)      */
+/*-----------------------------------------------------------------------*/
+#if _USE_FORWARD && _FS_TINY
+
+FRESULT f_forward (
+    FIL_t *fp,                         /* Pointer to the file object */
+    UINT (*func)(const BYTE*,UINT),    /* Pointer to the streaming function */
+    UINT btr,                        /* Number of bytes to forward */
+    UINT *bf                        /* Pointer to number of bytes forwarded */
+)
+{
+    FRESULT res;
+    DWORD remain, clst, sect;
+    UINT rcnt;
+    BYTE csect;
+
+
+    *bf = 0;    /* Initialize byte counter */
+
+    res = validate(fp->fs, fp->id);                    /* Check validity of the object */
+    if (res != FR_OK) LEAVE_FF(fp->fs, res);
+    if (fp->flag & FA__ERROR)                        /* Check error flag */
+        LEAVE_FF(fp->fs, FR_INT_ERR);
+    if (!(fp->flag & FA_READ))                        /* Check access mode */
+        LEAVE_FF(fp->fs, FR_DENIED);
+
+    remain = fp->fsize - fp->fptr;
+    if (btr > remain) btr = (UINT)remain;            /* Truncate btr by remaining bytes */
+
+    for ( ;  btr && (*func)(0, 0);                    /* Repeat until all data transferred or stream becomes busy */
+        fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
+        csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));    /* Sector offset in the cluster */
+        if ((fp->fptr % SS(fp->fs)) == 0) {            /* On the sector boundary? */
+            if (!csect) {                            /* On the cluster boundary? */
+                clst = (fp->fptr == 0) ?            /* On the top of the file? */
+                    fp->sclust : get_fat(fp->fs, fp->clust);
+                if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
+                if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
+                fp->clust = clst;                    /* Update current cluster */
+            }
+        }
+        sect = clust2sect(fp->fs, fp->clust);        /* Get current data sector */
+        if (!sect) ABORT(fp->fs, FR_INT_ERR);
+        sect += csect;
+        if (move_window(fp->fs, sect))                /* Move sector window */
+            ABORT(fp->fs, FR_DISK_ERR);
+        fp->dsect = sect;
+        rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs));    /* Forward data from sector window */
+        if (rcnt > btr) rcnt = btr;
+        rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
+        if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
+}
+
+    LEAVE_FF(fp->fs, FR_OK);
+}
+#endif /* _USE_FORWARD */
+
+
+
+#if _USE_MKFS && !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Create File System on the Drive                                       */
+/*-----------------------------------------------------------------------*/
+#define N_ROOTDIR    512        /* Number of root dir entries for FAT12/16 */
+#define N_FATS        1        /* Number of FAT copies (1 or 2) */
+
+
+FRESULT f_mkfs (
+    BYTE drv,            /* Logical drive number */
+    BYTE sfd,        /* Partitioning rule 0:FDISK, 1:SFD */
+    UINT au            /* Allocation unit size [bytes] */
+)
+{
+    static const WORD vst[] = { 1024,   512,  256,  128,   64,    32,   16,    8,    4,    2,   0};
+    static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512};
+    BYTE fmt, md, *tbl;
+    DWORD n_clst, vs, n, wsect;
+    UINT i;
+    DWORD b_vol, b_fat, b_dir, b_data;    /* Offset (LBA) */
+    DWORD n_vol, n_rsv, n_fat, n_dir;    /* Size */
+    FATFS *fs;
+    DSTATUS stat;
+
+
+    /* Check mounted drive and clear work area */
+    if (drv >= _VOLUMES) return FR_INVALID_DRIVE;
+    fs = FatFs[drv];
+    if (!fs) return FR_NOT_ENABLED;
+    fs->fs_type = 0;
+    drv = LD2PD(drv);
+
+    /* Get disk statics */
+    stat = disk_initialize(drv);
+    if (stat & STA_NOINIT) return FR_NOT_READY;
+    if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
+#if _MAX_SS != 512                    /* Get disk sector size */
+    if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK)
+        return FR_DISK_ERR;
+#endif
+    if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
+        return FR_DISK_ERR;
+    b_vol = (sfd) ? 0 : 63;    /* Volume start sector */
+    n_vol -= b_vol;
+    if (au & (au - 1)) au = 0;    /* Check validity of the AU size */
+    if (!au) {                    /* AU auto selection */
+        vs = n_vol / (2000 / (SS(fs) / 512));
+        for (i = 0; vs < vst[i]; i++) ;
+        au = cst[i];
+    }
+    au /= SS(fs);        /* Number of sectors per cluster */
+    if (au == 0) au = 1;
+    if (au > 128) au = 128;
+
+    /* Pre-compute number of clusters and FAT syb-type */
+    n_clst = n_vol / au;
+    fmt = FS_FAT12;
+    if (n_clst >= MIN_FAT16) fmt = FS_FAT16;
+    if (n_clst >= MIN_FAT32) fmt = FS_FAT32;
+
+    /* Determine offset and size of FAT structure */
+    if (fmt == FS_FAT32) {
+        n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
+        n_rsv = 32;
+        n_dir = 0;
+    } else {
+        n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
+        n_fat = (n_fat + SS(fs) - 1) / SS(fs);
+        n_rsv = 1;
+        n_dir = (DWORD)N_ROOTDIR * SZ_DIR / SS(fs);
+    }
+    b_fat = b_vol + n_rsv;                /* FAT area start sector */
+    b_dir = b_fat + n_fat * N_FATS;        /* Directory area start sector */
+    b_data = b_dir + n_dir;                /* Data area start sector */
+    if (n_vol < b_data + au) return FR_MKFS_ABORTED;    /* Too small volume */
+
+    /* Align data start sector to erase block boundary (for flash memory media) */
+    if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1;
+    n = (b_data + n - 1) & ~(n - 1);    /* Next nearest erase block from current data start */
+    n = (n - b_data) / N_FATS;
+    if (fmt == FS_FAT32) {        /* FAT32: Move FAT offset */
+        n_rsv += n;
+        b_fat += n;
+    } else {                    /* FAT12/16: Expand FAT size */
+        n_fat += n;
+    }
+
+    /* Determine number of clusters and final check of validity of the FAT sub-type */
+    n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
+    if (   (fmt == FS_FAT16 && n_clst < MIN_FAT16)
+        || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
+        return FR_MKFS_ABORTED;
+
+    /* Create partition table if required */
+    if (sfd) {    /* No patition table (SFD) */
+        md = 0xF0;
+    } else {    /* With patition table (FDISK) */
+        DWORD n_disk = b_vol + n_vol;
+
+        mem_set(fs->win, 0, SS(fs));
+        tbl = fs->win+MBR_Table;
+        ST_DWORD(tbl, 0x00010180);            /* Partition start in CHS */
+        if (n_disk < 63UL * 255 * 1024) {    /* Partition end in CHS */
+            n_disk = n_disk / 63 / 255;
+            tbl[7] = (BYTE)n_disk;
+            tbl[6] = (BYTE)((n_disk >> 2) | 63);
+        } else {
+            ST_WORD(&tbl[6], 0xFFFF);    /* CHS saturated */
+        }
+        tbl[5] = 254;
+        if (fmt != FS_FAT32)            /* System ID */
+            tbl[4] = (n_vol < 0x10000) ? 0x04 : 0x06;
+        else
+            tbl[4] = 0x0c;
+        ST_DWORD(tbl+8, 63);                /* Partition start in LBA */
+        ST_DWORD(tbl+12, n_vol);            /* Partition size in LBA */
+        ST_WORD(fs->win+BS_55AA, 0xAA55);    /* MBR signature */
+        if (disk_write(drv, fs->win, 0, 1) != RES_OK)    /* Put the MBR into first physical sector */
+            return FR_DISK_ERR;
+        md = 0xF8;
+    }
+
+    /* Create volume boot record */
+    tbl = fs->win;                            /* Clear sector */
+    mem_set(tbl, 0, SS(fs));
+    mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code, OEM name */
+    i = SS(fs);                                /* Sector size */
+    ST_WORD(tbl+BPB_BytsPerSec, i);
+    tbl[BPB_SecPerClus] = (BYTE)au;            /* Sectors per cluster */
+    ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv);        /* Reserved sectors */
+    tbl[BPB_NumFATs] = N_FATS;                    /* Number of FATs */
+    i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR;    /* Number of rootdir entries */
+    ST_WORD(tbl+BPB_RootEntCnt, i);
+    if (n_vol < 0x10000) {                    /* Number of total sectors */
+        ST_WORD(tbl+BPB_TotSec16, n_vol);
+    } else {
+        ST_DWORD(tbl+BPB_TotSec32, n_vol);
+    }
+    tbl[BPB_Media] = md;                    /* Media descriptor */
+    ST_WORD(tbl+BPB_SecPerTrk, 63);            /* Number of sectors per track */
+    ST_WORD(tbl+BPB_NumHeads, 255);            /* Number of heads */
+    ST_DWORD(tbl+BPB_HiddSec, b_vol);        /* Hidden sectors */
+    n = get_fattime();                        /* Use current time as VSN */
+    if (fmt == FS_FAT32) {
+        ST_DWORD(tbl+BS_VolID32, n);        /* VSN */
+        ST_DWORD(tbl+BPB_FATSz32, n_fat);    /* Number of sectors per FAT */
+        ST_DWORD(tbl+BPB_RootClus, 2);        /* Root directory start cluster (2) */
+        ST_WORD(tbl+BPB_FSInfo, 1);            /* FSInfo record offset (VBR+1) */
+        ST_WORD(tbl+BPB_BkBootSec, 6);        /* Backup boot record offset (VBR+6) */
+        tbl[BS_DrvNum32] = 0x80;                /* Drive number */
+        tbl[BS_BootSig32] = 0x29;                /* Extended boot signature */
+        mem_cpy(tbl+BS_VolLab32, "NO NAME    " "FAT32   ", 19);    /* Volume label, FAT signature */
+    } else {
+        ST_DWORD(tbl+BS_VolID, n);            /* VSN */
+        ST_WORD(tbl+BPB_FATSz16, n_fat);    /* Number of sectors per FAT */
+        tbl[BS_DrvNum] = 0x80;                /* Drive number */
+        tbl[BS_BootSig] = 0x29;                /* Extended boot signature */
+        mem_cpy(tbl+BS_VolLab, "NO NAME    " "FAT     ", 19);    /* Volume label, FAT signature */
+    }
+    ST_WORD(tbl+BS_55AA, 0xAA55);            /* Signature (Offset is fixed here regardless of sector size) */
+    if (disk_write(drv, tbl, b_vol, 1) != RES_OK)    /* Write VBR */
+        return FR_DISK_ERR;
+    if (fmt == FS_FAT32)                            /* Write backup VBR if needed (VBR+6) */
+        disk_write(drv, tbl, b_vol + 6, 1);
+
+    /* Initialize FAT area */
+    wsect = b_fat;
+    for (i = 0; i < N_FATS; i++) {        /* Initialize each FAT copy */
+        mem_set(tbl, 0, SS(fs));            /* 1st sector of the FAT  */
+        n = md;                                /* Media descriptor byte */
+        if (fmt != FS_FAT32) {
+            n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
+            ST_DWORD(tbl+0, n);                /* Reserve cluster #0-1 (FAT12/16) */
+        } else {
+            n |= 0xFFFFFF00;
+            ST_DWORD(tbl+0, n);                /* Reserve cluster #0-1 (FAT32) */
+            ST_DWORD(tbl+4, 0xFFFFFFFF);
+            ST_DWORD(tbl+8, 0x0FFFFFFF);    /* Reserve cluster #2 for root dir */
+        }
+        if (disk_write(drv, tbl, wsect++, 1) != RES_OK)
+            return FR_DISK_ERR;
+        mem_set(tbl, 0, SS(fs));            /* Fill following FAT entries with zero */
+        for (n = 1; n < n_fat; n++) {        /* This loop may take a time on FAT32 volume due to many single sector writes */
+            if (disk_write(drv, tbl, wsect++, 1) != RES_OK)
+                return FR_DISK_ERR;
+        }
+    }
+
+    /* Initialize root directory */
+    i = (fmt == FS_FAT32) ? au : n_dir;
+    do {
+        if (disk_write(drv, tbl, wsect++, 1) != RES_OK)
+            return FR_DISK_ERR;
+    } while (--i);
+
+#if _USE_ERASE    /* Erase data area if needed */
+    {
+        DWORD eb[2];
+
+        eb[0] = wsect; eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
+        disk_ioctl(drv, CTRL_ERASE_SECTOR, eb);
+    }
+#endif
+
+    /* Create FSInfo if needed */
+    if (fmt == FS_FAT32) {
+        ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
+        ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
+        ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);    /* Number of free clusters */
+        ST_DWORD(tbl+FSI_Nxt_Free, 2);                /* Last allocated cluster# */
+        ST_WORD(tbl+BS_55AA, 0xAA55);
+        disk_write(drv, tbl, b_vol + 1, 1);    /* Write original (VBR+1) */
+        disk_write(drv, tbl, b_vol + 7, 1);    /* Write backup (VBR+7) */
+    }
+
+    return (disk_ioctl(drv, CTRL_SYNC, (void*)0) == RES_OK) ? FR_OK : FR_DISK_ERR;
+}
+
+#endif /* _USE_MKFS && !_FS_READONLY */
+
+
+
+
+#if _USE_STRFUNC
+/*-----------------------------------------------------------------------*/
+/* Get a string from the file                                            */
+/*-----------------------------------------------------------------------*/
+TCHAR* f_gets (
+    TCHAR* buff,    /* Pointer to the string buffer to read */
+    int len,        /* Size of string buffer (characters) */
+    FIL_t* fil    /* Pointer to the file object */
+)
+{
+    int n = 0;
+    TCHAR c, *p = buff;
+    BYTE s[2];
+    UINT rc;
+
+
+    while (n < len - 1) {            /* Read bytes until buffer gets filled */
+        f_read(fil, s, 1, &rc);
+        if (rc != 1) break;            /* Break on EOF or error */
+        c = s[0];
+#if _LFN_UNICODE                    /* Read a character in UTF-8 encoding */
+        if (c >= 0x80) {
+            if (c < 0xC0) continue;    /* Skip stray trailer */
+            if (c < 0xE0) {            /* Two-byte sequense */
+                f_read(fil, s, 1, &rc);
+                if (rc != 1) break;
+                c = ((c & 0x1F) << 6) | (s[0] & 0x3F);
+                if (c < 0x80) c = '?';
+            } else {
+                if (c < 0xF0) {        /* Three-byte sequense */
+                    f_read(fil, s, 2, &rc);
+                    if (rc != 2) break;
+                    c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F);
+                    if (c < 0x800) c = '?';
+                } else {            /* Reject four-byte sequense */
+                    c = '?';
+                }
+            }
+        }
+#endif
+#if _USE_STRFUNC >= 2
+        if (c == '\r') continue;    /* Strip '\r' */
+#endif
+        *p++ = c;
+        n++;
+        if (c == '\n') break;        /* Break on EOL */
+    }
+    *p = 0;
+    return n ? buff : 0;            /* When no data read (eof or error), return with error. */
+}
+
+
+
+#if !_FS_READONLY
+#include <stdarg.h>
+/*-----------------------------------------------------------------------*/
+/* Put a character to the file                                           */
+/*-----------------------------------------------------------------------*/
+int f_putc (
+    TCHAR c,    /* A character to be output */
+    FIL_t* fil    /* Pointer to the file object */
+)
+{
+    UINT bw, btw;
+    BYTE s[3];
+
+
+#if _USE_STRFUNC >= 2
+    if (c == '\n') f_putc ('\r', fil);    /* LF -> CRLF conversion */
+#endif
+
+#if _LFN_UNICODE    /* Write the character in UTF-8 encoding */
+    if (c < 0x80) {            /* 7-bit */
+        s[0] = (BYTE)c;
+        btw = 1;
+    } else {
+        if (c < 0x800) {    /* 11-bit */
+            s[0] = (BYTE)(0xC0 | (c >> 6));
+            s[1] = (BYTE)(0x80 | (c & 0x3F));
+            btw = 2;
+        } else {            /* 16-bit */
+            s[0] = (BYTE)(0xE0 | (c >> 12));
+            s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F));
+            s[2] = (BYTE)(0x80 | (c & 0x3F));
+            btw = 3;
+    }
+    }
+#else                /* Write the character without conversion */
+    s[0] = (BYTE)c;
+    btw = 1;
+#endif
+    f_write(fil, s, btw, &bw);        /* Write the char to the file */
+    return (bw == btw) ? 1 : EOF;    /* Return the result */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a string to the file                                              */
+/*-----------------------------------------------------------------------*/
+int f_puts (
+    const TCHAR* str,    /* Pointer to the string to be output */
+    FIL_t* fil            /* Pointer to the file object */
+)
+{
+    int n;
+
+
+    for (n = 0; *str; str++, n++) {
+        if (f_putc(*str, fil) == EOF) return EOF;
+    }
+    return n;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Put a formatted string to the file                                    */
+/*-----------------------------------------------------------------------*/
+int f_printf (
+    FIL_t* fil,            /* Pointer to the file object */
+    const TCHAR* str,    /* Pointer to the format string */
+    ...                    /* Optional arguments... */
+)
+{
+    va_list arp;
+    BYTE f, r;
+    UINT i, j, w;
+    ULONG v;
+    TCHAR c, d, s[16], *p;
+    int res, cc;
+
+
+    va_start(arp, str);
+
+    for (cc = res = 0; cc != EOF; res += cc) {
+        c = *str++;
+        if (c == 0) break;            /* End of string */
+        if (c != '%') {                /* Non escape character */
+            cc = f_putc(c, fil);
+            if (cc != EOF) cc = 1;
+            continue;
+        }
+        w = f = 0;
+        c = *str++;
+        if (c == '0') {                /* Flag: '0' padding */
+            f = 1; c = *str++;
+        } else {
+            if (c == '-') {            /* Flag: left justified */
+                f = 2; c = *str++;
+        }
+        }
+        while (IsDigit(c)) {        /* Precision */
+            w = w * 10 + c - '0';
+            c = *str++;
+        }
+        if (c == 'l' || c == 'L') {    /* Prefix: Size is long int */
+            f |= 4; c = *str++;
+        }
+        if (!c) break;
+        d = c;
+        if (IsLower(d)) d -= 0x20;
+        switch (d) {                /* Type is... */
+        case 'S' :                    /* String */
+            p = va_arg(arp, TCHAR*);
+            for (j = 0; p[j]; j++) ;
+            res = 0;
+            while (!(f & 2) && j++ < w) res += (cc = f_putc(' ', fil));
+            res += (cc = f_puts(p, fil));
+            while (j++ < w) res += (cc = f_putc(' ', fil));
+            if (cc != EOF) cc = res;
+            continue;
+        case 'C' :                    /* Character */
+            cc = f_putc((TCHAR)va_arg(arp, int), fil); continue;
+        case 'B' :                    /* Binary */
+            r = 2; break;
+        case 'O' :                    /* Octal */
+            r = 8; break;
+        case 'D' :                    /* Signed decimal */
+        case 'U' :                    /* Unsigned decimal */
+            r = 10; break;
+        case 'X' :                    /* Hexdecimal */
+            r = 16; break;
+        default:                    /* Unknown type (passthrough) */
+            cc = f_putc(c, fil); continue;
+        }
+
+        /* Get an argument and put it in numeral */
+        v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : va_arg(arp, unsigned int));
+        if (d == 'D' && (v & 0x80000000)) {
+            v = 0 - v;
+            f |= 8;
+        }
+        i = 0;
+        do {
+            d = (TCHAR)(v % r); v /= r;
+            if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
+            s[i++] = d + '0';
+        } while (v && i < sizeof(s) / sizeof(s[0]));
+        if (f & 8) s[i++] = '-';
+        j = i; d = (f & 1) ? '0' : ' ';
+        res = 0;
+        while (!(f & 2) && j++ < w) res += (cc = f_putc(d, fil));
+        do res += (cc = f_putc(s[--i], fil)); while(i);
+        while (j++ < w) res += (cc = f_putc(' ', fil));
+        if (cc != EOF) cc = res;
+    }
+
+    va_end(arp);
+    return (cc == EOF) ? cc : res;
+}
+
+#endif /* !_FS_READONLY */
+#endif /* _USE_STRFUNC */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/ff.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,337 @@
+/*---------------------------------------------------------------------------/
+/  FatFs - FAT file system module include file  R0.08b    (C)ChaN, 2011
+/----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following trems.
+/
+/  Copyright (C) 2011, ChaN, all right reserved.
+/
+/ * The 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 product UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/----------------------------------------------------------------------------*/
+
+#ifndef _FATFS
+#define _FATFS    8237    /* Revision ID */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "integer.h"    /* Basic integer types */
+#include "ffconf.h"        /* FatFs configuration options */
+
+#if _FATFS != _FFCONF
+#error Wrong configuration file (ffconf.h).
+#endif
+
+
+
+#define _DRIVES        4
+/* Number of logical drives to be used. This affects the size of internal table. */
+/* Definitions of volume management */
+
+#if _MULTI_PARTITION        /* Multiple partition configuration */
+#define LD2PD(vol) (VolToPart[vol].pd)    /* Get physical drive# */
+#define LD2PT(vol) (VolToPart[vol].pt)    /* Get partition# */
+typedef struct {
+    BYTE pd;    /* Physical drive# */
+    BYTE pt;    /* Partition # (0-3) */
+} PARTITION;
+extern const PARTITION VolToPart[];    /* Volume - Physical location resolution table */
+
+#else                        /* Single partition configuration */
+#define LD2PD(vol) (vol)    /* Logical drive# is bound to the same physical drive# */
+#define LD2PT(vol) 0        /* Always mounts the 1st partition */
+
+#endif
+
+
+
+/* Type of path name strings on FatFs API */
+
+#if _LFN_UNICODE            /* Unicode string */
+#if !_USE_LFN
+#error _LFN_UNICODE must be 0 in non-LFN cfg.
+#endif
+#ifndef _INC_TCHAR
+typedef WCHAR TCHAR;
+#define _T(x) L ## x
+#define _TEXT(x) L ## x
+#endif
+
+#else                        /* ANSI/OEM string */
+#ifndef _INC_TCHAR
+typedef char TCHAR;
+#define _T(x) x
+#define _TEXT(x) x
+#endif
+
+#endif
+
+
+
+/* File system object structure (FATFS) */
+
+typedef struct {
+    BYTE    fs_type;        /* FAT sub-type (0:Not mounted) */
+    BYTE    drv;            /* Physical drive number */
+    BYTE    csize;            /* Sectors per cluster (1,2,4...128) */
+    BYTE    n_fats;            /* Number of FAT copies (1,2) */
+    BYTE    wflag;            /* win[] dirty flag (1:must be written back) */
+    BYTE    fsi_flag;        /* fsinfo dirty flag (1:must be written back) */
+    WORD    id;                /* File system mount ID */
+    WORD    n_rootdir;        /* Number of root directory entries (FAT12/16) */
+#if _MAX_SS != 512
+    WORD    ssize;            /* Bytes per sector (512,1024,2048,4096) */
+#endif
+#if _FS_REENTRANT
+    _SYNC_t    sobj;            /* Identifier of sync object */
+#endif
+#if !_FS_READONLY
+    DWORD    last_clust;        /* Last allocated cluster */
+    DWORD    free_clust;        /* Number of free clusters */
+    DWORD    fsi_sector;        /* fsinfo sector (FAT32) */
+#endif
+#if _FS_RPATH
+    DWORD    cdir;            /* Current directory start cluster (0:root) */
+#endif
+    DWORD    n_fatent;        /* Number of FAT entries (= number of clusters + 2) */
+    DWORD    fsize;            /* Sectors per FAT */
+    DWORD    fatbase;        /* FAT start sector */
+    DWORD    dirbase;        /* Root directory start sector (FAT32:Cluster#) */
+    DWORD    database;        /* Data start sector */
+    DWORD    winsect;        /* Current sector appearing in the win[] */
+    BYTE    win[_MAX_SS];    /* Disk access window for Directory, FAT (and Data on tiny cfg) */
+} FATFS;
+
+
+
+/* File object structure (FIL) */
+
+typedef struct {
+    FATFS*    fs;                /* Pointer to the owner file system object */
+    WORD    id;                /* Owner file system mount ID */
+    BYTE    flag;            /* File status flags */
+    BYTE    pad1;
+    DWORD    fptr;            /* File read/write pointer (0 on file open) */
+    DWORD    fsize;            /* File size */
+    DWORD    sclust;            /* File start cluster (0 when fsize==0) */
+    DWORD    clust;            /* Current cluster */
+    DWORD    dsect;            /* Current data sector */
+#if !_FS_READONLY
+    DWORD    dir_sect;        /* Sector containing the directory entry */
+    BYTE*    dir_ptr;        /* Ponter to the directory entry in the window */
+#endif
+#if _USE_FASTSEEK
+    DWORD*    cltbl;            /* Pointer to the cluster link map table (null on file open) */
+#endif
+#if _FS_SHARE
+    UINT    lockid;            /* File lock ID (index of file semaphore table) */
+#endif
+#if !_FS_TINY
+    BYTE    buf[_MAX_SS];    /* File data read/write buffer */
+#endif
+} FIL_t;
+
+
+
+/* Directory object structure (DIR) */
+
+typedef struct {
+    FATFS*    fs;                /* Pointer to the owner file system object */
+    WORD    id;                /* Owner file system mount ID */
+    WORD    index;            /* Current read/write index number */
+    DWORD    sclust;            /* Table start cluster (0:Root dir) */
+    DWORD    clust;            /* Current cluster */
+    DWORD    sect;            /* Current sector */
+    BYTE*    dir;            /* Pointer to the current SFN entry in the win[] */
+    BYTE*    fn;                /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
+#if _USE_LFN
+    WCHAR*    lfn;            /* Pointer to the LFN working buffer */
+    WORD    lfn_idx;        /* Last matched LFN index number (0xFFFF:No LFN) */
+#endif
+} DIR_t;
+
+
+
+/* File status structure (FILINFO) */
+
+typedef struct {
+    DWORD    fsize;            /* File size */
+    WORD    fdate;            /* Last modified date */
+    WORD    ftime;            /* Last modified time */
+    BYTE    fattrib;        /* Attribute */
+    TCHAR    fname[13];        /* Short file name (8.3 format) */
+#if _USE_LFN
+    TCHAR*    lfname;            /* Pointer to the LFN buffer */
+    UINT     lfsize;            /* Size of LFN buffer in TCHAR */
+#endif
+} FILINFO;
+
+
+
+/* File function return code (FRESULT) */
+
+typedef enum {
+    FR_OK = 0,                /* (0) Succeeded */
+    FR_DISK_ERR,            /* (1) A hard error occured in the low level disk I/O layer */
+    FR_INT_ERR,                /* (2) Assertion failed */
+    FR_NOT_READY,            /* (3) The physical drive cannot work */
+    FR_NO_FILE,                /* (4) Could not find the file */
+    FR_NO_PATH,                /* (5) Could not find the path */
+    FR_INVALID_NAME,        /* (6) The path name format is invalid */
+    FR_DENIED,                /* (7) Acces denied due to prohibited access or directory full */
+    FR_EXIST,                /* (8) Acces denied due to prohibited access */
+    FR_INVALID_OBJECT,        /* (9) The file/directory object is invalid */
+    FR_WRITE_PROTECTED,        /* (10) The physical drive is write protected */
+    FR_INVALID_DRIVE,        /* (11) The logical drive number is invalid */
+    FR_NOT_ENABLED,            /* (12) The volume has no work area */
+    FR_NO_FILESYSTEM,        /* (13) There is no valid FAT volume on the physical drive */
+    FR_MKFS_ABORTED,        /* (14) The f_mkfs() aborted due to any parameter error */
+    FR_TIMEOUT,                /* (15) Could not get a grant to access the volume within defined period */
+    FR_LOCKED,                /* (16) The operation is rejected according to the file shareing policy */
+    FR_NOT_ENOUGH_CORE,        /* (17) LFN working buffer could not be allocated */
+    FR_TOO_MANY_OPEN_FILES    /* (18) Number of open files > _FS_SHARE */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* FatFs module application interface                  */
+
+FRESULT f_mount (BYTE, FATFS*);                        /* Mount/Unmount a logical drive */
+FRESULT f_open (FIL_t*, const TCHAR*, BYTE);            /* Open or create a file */
+FRESULT f_read (FIL_t*, void*, UINT, UINT*);            /* Read data from a file */
+FRESULT f_lseek (FIL_t*, DWORD);                        /* Move file pointer of a file object */
+FRESULT f_close (FIL_t*);                                /* Close an open file object */
+FRESULT f_opendir (DIR_t*, const TCHAR*);                /* Open an existing directory */
+FRESULT f_readdir (DIR_t*, FILINFO*);                    /* Read a directory item */
+FRESULT f_stat (const TCHAR*, FILINFO*);            /* Get file status */
+FRESULT f_write (FIL_t*, const void*, UINT, UINT*);    /* Write data to a file */
+FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**);    /* Get number of free clusters on the drive */
+FRESULT f_truncate (FIL_t*);                            /* Truncate file */
+FRESULT f_sync (FIL_t*);                                /* Flush cached data of a writing file */
+FRESULT f_unlink (const TCHAR*);                    /* Delete an existing file or directory */
+FRESULT f_mkdir (const TCHAR*);                        /* Create a new directory */
+FRESULT f_chmod (const TCHAR*, BYTE, BYTE);            /* Change attriburte of the file/dir */
+FRESULT f_utime (const TCHAR*, const FILINFO*);        /* Change timestamp of the file/dir */
+FRESULT f_rename (const TCHAR*, const TCHAR*);        /* Rename/Move a file or directory */
+FRESULT f_forward (FIL_t*, UINT(*)(const BYTE*,UINT), UINT, UINT*);    /* Forward data to the stream */
+FRESULT f_mkfs (BYTE, BYTE, UINT);                    /* Create a file system on the drive */
+FRESULT f_chdrive (BYTE);                            /* Change current drive */
+FRESULT f_chdir (const TCHAR*);                        /* Change current directory */
+FRESULT f_getcwd (TCHAR*, UINT);                    /* Get current directory */
+int f_putc (TCHAR, FIL_t*);                            /* Put a character to the file */
+int f_puts (const TCHAR*, FIL_t*);                    /* Put a string to the file */
+int f_printf (FIL_t*, const TCHAR*, ...);                /* Put a formatted string to the file */
+TCHAR* f_gets (TCHAR*, int, FIL_t*);                    /* Get a string from the file */
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
+#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
+#define f_tell(fp) ((fp)->fptr)
+#define f_size(fp) ((fp)->fsize)
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Additional user defined functions                            */
+
+/* RTC function */
+#if !_FS_READONLY
+DWORD get_fattime (void);
+#endif
+
+/* Unicode support functions */
+#if _USE_LFN                        /* Unicode - OEM code conversion */
+WCHAR ff_convert (WCHAR, UINT);        /* OEM-Unicode bidirectional conversion */
+WCHAR ff_wtoupper (WCHAR);            /* Unicode upper-case conversion */
+#if _USE_LFN == 3                    /* Memory functions */
+void* ff_memalloc (UINT);            /* Allocate memory block */
+void ff_memfree (void*);            /* Free memory block */
+#endif
+#endif
+
+/* Sync functions */
+#if _FS_REENTRANT
+int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */
+int ff_req_grant (_SYNC_t);            /* Lock sync object */
+void ff_rel_grant (_SYNC_t);        /* Unlock sync object */
+int ff_del_syncobj (_SYNC_t);        /* Delete a sync object */
+#endif
+
+
+
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address                                     */
+
+
+/* File access control and file status flags (FIL.flag) */
+
+#define    FA_READ                0x01
+#define    FA_OPEN_EXISTING    0x00
+#define FA__ERROR            0x80
+
+#if !_FS_READONLY
+#define    FA_WRITE            0x02
+#define    FA_CREATE_NEW        0x04
+#define    FA_CREATE_ALWAYS    0x08
+#define    FA_OPEN_ALWAYS        0x10
+#define FA__WRITTEN            0x20
+#define FA__DIRTY            0x40
+#endif
+
+
+/* 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 */
+
+
+/* Fast seek function */
+#define CREATE_LINKMAP    0xFFFFFFFF
+
+
+
+/*--------------------------------*/
+/* Multi-byte word access macros  */
+
+#if _WORD_ACCESS == 1    /* Enable word access to the FAT structure */
+#define    LD_WORD(ptr)        (WORD)(*(WORD*)(BYTE*)(ptr))
+#define    LD_DWORD(ptr)        (DWORD)(*(DWORD*)(BYTE*)(ptr))
+#define    ST_WORD(ptr,val)    *(WORD*)(BYTE*)(ptr)=(WORD)(val)
+#define    ST_DWORD(ptr,val)    *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
+#else                    /* Use byte-by-byte access to the FAT structure */
+#define    LD_WORD(ptr)        (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
+#define    LD_DWORD(ptr)        (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
+#define    ST_WORD(ptr,val)    *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
+#define    ST_DWORD(ptr,val)    *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FATFS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/ffconf.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,189 @@
+/*---------------------------------------------------------------------------/
+/  FatFs - FAT file system module configuration file  R0.08b (C)ChaN, 2011
+/----------------------------------------------------------------------------/
+/
+/ CAUTION! Do not forget to make clean the project after any changes to
+/ the configuration options.
+/
+/----------------------------------------------------------------------------*/
+#ifndef _FFCONF
+#define _FFCONF 8237    /* Revision ID */
+
+
+/*---------------------------------------------------------------------------/
+/ Function and Buffer Configurations
+/----------------------------------------------------------------------------*/
+
+#define    _FS_TINY        0    /* 0:Normal or 1:Tiny */
+/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
+/  object instead of the sector buffer in the individual file object for file
+/  data transfer. This reduces memory consumption 512 bytes each file object. */
+
+
+#define _FS_READONLY    0    /* 0:Read/Write or 1:Read only */
+/* Setting _FS_READONLY to 1 defines read only configuration. This removes
+/  writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
+/  f_truncate and useless f_getfree. */
+
+
+#define _FS_MINIMIZE    0    /* 0 to 3 */
+/* The _FS_MINIMIZE option defines minimization level to remove some functions.
+/
+/   0: Full function.
+/   1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
+/      are removed.
+/   2: f_opendir and f_readdir are removed in addition to 1.
+/   3: f_lseek is removed in addition to 2. */
+
+
+#define    _USE_STRFUNC    1    /* 0:Disable or 1/2:Enable */
+/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
+
+
+#define    _USE_MKFS        1    /* 0:Disable or 1:Enable */
+/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
+
+
+#define    _USE_FORWARD    0    /* 0:Disable or 1:Enable */
+/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
+
+
+#define    _USE_FASTSEEK    0    /* 0:Disable or 1:Enable */
+/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/----------------------------------------------------------------------------*/
+
+#define _CODE_PAGE    1252
+/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
+/  Incorrect setting of the code page can cause a file open failure.
+/
+/   932  - Japanese Shift-JIS (DBCS, OEM, Windows)
+/   936  - Simplified Chinese GBK (DBCS, OEM, Windows)
+/   949  - Korean (DBCS, OEM, Windows)
+/   950  - Traditional Chinese Big5 (DBCS, OEM, Windows)
+/   1250 - Central Europe (Windows)
+/   1251 - Cyrillic (Windows)
+/   1252 - Latin 1 (Windows)
+/   1253 - Greek (Windows)
+/   1254 - Turkish (Windows)
+/   1255 - Hebrew (Windows)
+/   1256 - Arabic (Windows)
+/   1257 - Baltic (Windows)
+/   1258 - Vietnam (OEM, Windows)
+/   437  - U.S. (OEM)
+/   720  - Arabic (OEM)
+/   737  - Greek (OEM)
+/   775  - Baltic (OEM)
+/   850  - Multilingual Latin 1 (OEM)
+/   858  - Multilingual Latin 1 + Euro (OEM)
+/   852  - Latin 2 (OEM)
+/   855  - Cyrillic (OEM)
+/   866  - Russian (OEM)
+/   857  - Turkish (OEM)
+/   862  - Hebrew (OEM)
+/   874  - Thai (OEM, Windows)
+/    1    - ASCII only (Valid for non LFN cfg.)
+*/
+
+
+#define    _USE_LFN    1        /* 0 to 3 */
+#define    _MAX_LFN    255        /* Maximum LFN length to handle (12 to 255) */
+/* The _USE_LFN option switches the LFN support.
+/
+/   0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
+/   1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
+/   2: Enable LFN with dynamic working buffer on the STACK.
+/   3: Enable LFN with dynamic working buffer on the HEAP.
+/
+/  The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
+/  Unicode handling functions ff_convert() and ff_wtoupper() must be added
+/  to the project. When enable to use heap, memory control functions
+/  ff_memalloc() and ff_memfree() must be added to the project. */
+
+
+#define    _LFN_UNICODE    0    /* 0:ANSI/OEM or 1:Unicode */
+/* To switch the character code set on FatFs API to Unicode,
+/  enable LFN feature and set _LFN_UNICODE to 1. */
+
+
+#define _FS_RPATH        0    /* 0 to 2 */
+/* The _FS_RPATH option configures relative path feature.
+/
+/   0: Disable relative path feature and remove related functions.
+/   1: Enable relative path. f_chdrive() and f_chdir() are available.
+/   2: f_getcwd() is available in addition to 1.
+/
+/  Note that output of the f_readdir fnction is affected by this option. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Physical Drive Configurations
+/----------------------------------------------------------------------------*/
+
+#define _VOLUMES    1
+/* Number of volumes (logical drives) to be used. */
+
+
+#define    _MAX_SS        512        /* 512, 1024, 2048 or 4096 */
+/* Maximum sector size to be handled.
+/  Always set 512 for memory card and hard disk but a larger value may be
+/  required for on-board flash memory, floppy disk and optical disk.
+/  When _MAX_SS is larger than 512, it configures FatFs to variable sector size
+/  and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */
+
+
+#define    _MULTI_PARTITION    0    /* 0:Single partition or 1:Multiple partition */
+/* When set to 0, each volume is bound to the same physical drive number and
+/ it can mount only first primaly partition. When it is set to 1, each volume
+/ is tied to the partitions listed in VolToPart[]. */
+
+
+#define    _USE_ERASE    0    /* 0:Disable or 1:Enable */
+/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
+/  should be added to the disk_ioctl functio. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/----------------------------------------------------------------------------*/
+
+#define _WORD_ACCESS    0    /* 0 or 1 */
+/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
+/  option defines which access method is used to the word data on the FAT volume.
+/
+/   0: Byte-by-byte access.
+/   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 size. */
+
+
+/* A header file that defines sync object types on the O/S, such as
+/  windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */
+
+#define _FS_REENTRANT    0        /* 0:Disable or 1:Enable */
+#define _FS_TIMEOUT        1000    /* Timeout period in unit of time ticks */
+#define    _SYNC_t            HANDLE    /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
+
+/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module.
+/
+/   0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
+/   1: Enable reentrancy. Also user provided synchronization handlers,
+/      ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
+/      function must be added to the project. */
+
+
+#define    _FS_SHARE    0    /* 0:Disable or >=1:Enable */
+/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value
+   defines how many files can be opened simultaneously. */
+
+
+#endif /* _FFCONFIG */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/integer.h	Tue Nov 22 05:45:58 2011 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/CHAN_FS/option/ccsbcs.c	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,540 @@
+/*------------------------------------------------------------------------*/
+/* Unicode - Local code bidirectional converter  (C)ChaN, 2009            */
+/* (SBCS code pages)                                                      */
+/*------------------------------------------------------------------------*/
+/*  437   U.S. (OEM)
+/   720   Arabic (OEM)
+/   1256  Arabic (Windows)
+/   737   Greek (OEM)
+/   1253  Greek (Windows)
+/   1250  Central Europe (Windows)
+/   775   Baltic (OEM)
+/   1257  Baltic (Windows)
+/   850   Multilingual Latin 1 (OEM)
+/   852   Latin 2 (OEM)
+/   1252  Latin 1 (Windows)
+/   855   Cyrillic (OEM)
+/   1251  Cyrillic (Windows)
+/   866   Russian (OEM)
+/   857   Turkish (OEM)
+/   1254  Turkish (Windows)
+/   858   Multilingual Latin 1 + Euro (OEM)
+/   862   Hebrew (OEM)
+/   1255  Hebrew (Windows)
+/   874   Thai (OEM, Windows)
+/   1258  Vietnam (OEM, Windows)
+*/
+
+#include "../ff.h"
+
+
+#if _CODE_PAGE == 437
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP437(0x80-0xFF) to Unicode conversion table */
+	0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+	0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+	0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+	0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
+	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+	0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+	0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+	0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+	0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+	0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+	0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+	0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+	0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 720
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP720(0x80-0xFF) to Unicode conversion table */
+	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,
+	0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+	0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+	0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+	0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+	0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+	0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642,
+	0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
+	0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0xO650, 0x2248,
+	0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 737
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP737(0x80-0xFF) to Unicode conversion table */
+	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,
+	0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
+	0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+	0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+	0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+	0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+	0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD,
+	0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
+	0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248,
+	0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 775
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP775(0x80-0xFF) to Unicode conversion table */
+	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,
+	0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6,
+	0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118,
+	0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
+	0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B,
+	0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+	0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144,
+	0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
+	0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E,
+	0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 850
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP850(0x80-0xFF) to Unicode conversion table */
+	0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+	0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+	0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+	0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+	0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+	0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+	0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
+	0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+	0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+	0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+	0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+	0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 852
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP852(0x80-0xFF) to Unicode conversion table */
+	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,
+	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E,
+	0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A,
+	0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+	0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE,
+	0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
+	0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161,
+	0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
+	0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8,
+	0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 855
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP855(0x80-0xFF) to Unicode conversion table */
+	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,
+	0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414,
+	0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438,
+	0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+	0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E,
+	0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
+	0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443,
+	0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
+	0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D,
+	0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 857
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP857(0x80-0xFF) to Unicode conversion table */
+	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,
+	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F,
+	0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+	0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+	0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE,
+	0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
+	0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000,
+	0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
+	0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+	0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 858
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP858(0x80-0xFF) to Unicode conversion table */
+	0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
+	0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
+	0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
+	0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
+	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+	0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
+	0x00A9, 0x2563, 0x2551, 0x2557, 0x2550, 0x00A2, 0x00A5, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
+	0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE,
+	0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00C6, 0x00CC, 0x2580,
+	0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
+	0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
+	0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
+	0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 862
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP862(0x80-0xFF) to Unicode conversion table */
+	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,
+	0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+	0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+	0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+	0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+	0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+	0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
+	0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
+	0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+	0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 866
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP866(0x80-0xFF) to Unicode conversion table */
+	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,
+	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+	0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+	0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+	0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
+	0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
+	0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+	0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
+	0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
+	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+	0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+	0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E,
+	0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
+};
+
+#elif _CODE_PAGE == 874
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP874(0x80-0xFF) to Unicode conversion table */
+	0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
+	0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
+	0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
+	0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
+	0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+	0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+	0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+	0x0E38, 0x0E39, 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F,
+	0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+	0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+	0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+	0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+#elif _CODE_PAGE == 1250
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP1250(0x80-0xFF) to Unicode conversion table */
+	0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+	0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,
+	0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,
+	0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7,
+	0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,
+	0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+	0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,
+	0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
+	0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+	0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+	0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+	0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+	0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+	0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+	0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
+};
+
+#elif _CODE_PAGE == 1251
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP1251(0x80-0xFF) to Unicode conversion table */
+	0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
+	0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
+	0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x0000, 0x2111, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
+	0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
+	0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
+	0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
+	0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
+	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,
+	0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+	0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+	0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+	0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F
+};
+
+#elif _CODE_PAGE == 1252
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP1252(0x80-0xFF) to Unicode conversion table */
+	0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+	0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000,
+	0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178,
+	0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+	0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+	0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+	0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+	0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+	0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+	0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+	0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+	0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+	0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+	0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
+};
+
+#elif _CODE_PAGE == 1253
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP1253(0x80-0xFF) to Unicode conversion table */
+	0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+	0x0000, 0x2030, 0x0000, 0x2039, 0x000C, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+	0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,
+	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7,
+	0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
+	0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+	0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+	0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+	0x03A8, 0x03A9, 0x03AA, 0x03AD, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+	0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+	0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+	0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+	0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000
+};
+
+#elif _CODE_PAGE == 1254
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP1254(0x80-0xFF) to Unicode conversion table */
+	0x20AC, 0x0000, 0x210A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+	0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+	0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+	0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+	0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+	0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+	0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+	0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+	0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x0130, 0x015E, 0x00DF,
+	0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+	0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+	0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+	0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
+};
+
+#elif _CODE_PAGE == 1255
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP1255(0x80-0xFF) to Unicode conversion table */
+	0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+	0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+	0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+	0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+	0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+	0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+	0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3,
+	0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	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, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000
+};
+
+#elif _CODE_PAGE == 1256
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP1256(0x80-0xFF) to Unicode conversion table */
+	0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+	0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
+	0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,
+	0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+	0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+	0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,
+	0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+	0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+	0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7,
+	0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0640, 0x0642, 0x0643,
+	0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7,
+	0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,
+	0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7,
+	0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2
+}
+
+#elif _CODE_PAGE == 1257
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP1257(0x80-0xFF) to Unicode conversion table */
+	0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
+	0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8,
+	0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000,
+	0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7,
+	0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+	0x00B8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
+	0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
+	0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
+	0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
+	0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
+	0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
+	0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
+	0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
+	0x0173, 0x014E, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9
+};
+
+#elif _CODE_PAGE == 1258
+#define _TBLDEF 1
+static
+const WCHAR Tbl[] = {	/*  CP1258(0x80-0xFF) to Unicode conversion table */
+	0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+	0x02C6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+	0x02DC, 0x2122, 0x0000, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
+	0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+	0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+	0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+	0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+	0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+	0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
+	0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
+	0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
+	0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+	0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
+	0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
+	0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF
+};
+
+#endif
+
+
+#if !_TBLDEF || !_USE_LFN
+#error This file is not needed in current configuration. Remove from the project.
+#endif
+
+
+WCHAR ff_convert (	/* Converted character, Returns zero on error */
+	WCHAR	src,	/* Character code to be converted */
+	UINT	dir		/* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
+)
+{
+	WCHAR c;
+
+
+	if (src < 0x80) {	/* ASCII */
+		c = src;
+
+	} else {
+		if (dir) {		/* OEMCP to Unicode */
+			c = (src >= 0x100) ? 0 : Tbl[src - 0x80];
+
+		} else {		/* Unicode to OEMCP */
+			for (c = 0; c < 0x80; c++) {
+				if (src == Tbl[c]) break;
+			}
+			c = (c + 0x80) & 0xFF;
+		}
+	}
+
+	return c;
+}
+
+
+WCHAR ff_wtoupper (	/* Upper converted character */
+	WCHAR chr		/* Input character */
+)
+{
+	static const WCHAR tbl_lower[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0x00A2, 0x00A3, 0x00A5, 0x00AC, 0x00AF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x0FF, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x10D, 0x10F, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11B, 0x11D, 0x11F, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12B, 0x12D, 0x12F, 0x131, 0x133, 0x135, 0x137, 0x13A, 0x13C, 0x13E, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14B, 0x14D, 0x14F, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15B, 0x15D, 0x15F, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16B, 0x16D, 0x16F, 0x171, 0x173, 0x175, 0x177, 0x17A, 0x17C, 0x17E, 0x192, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CA, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45A, 0x45B, 0x45C, 0x45E, 0x45F, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0 };
+	static const WCHAR tbl_upper[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x21, 0xFFE0, 0xFFE1, 0xFFE5, 0xFFE2, 0xFFE3, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C, 0x10E, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11A, 0x11C, 0x11E, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x132, 0x134, 0x136, 0x139, 0x13B, 0x13D, 0x13F, 0x141, 0x143, 0x145, 0x147, 0x14A, 0x14C, 0x14E, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15A, 0x15C, 0x15E, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16A, 0x16C, 0x16E, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17B, 0x17D, 0x191, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3AA, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40A, 0x40B, 0x40C, 0x40E, 0x40F, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0 };
+	int i;
+
+
+	for (i = 0; tbl_lower[i] && chr != tbl_lower[i]; i++) ;
+
+	return tbl_lower[i] ? tbl_upper[i] : chr;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATDirHandle.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,61 @@
+/* mbed Microcontroller Library - FATDirHandle
+ * Copyright (c) 2008, sford
+ */
+ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ff.h"
+#include "FATDirHandle.h"
+#include "FATFileSystem.h"
+
+namespace mbed {
+
+FATDirHandle::FATDirHandle(const DIR_t &the_dir) {
+    dir = the_dir;
+}
+
+int FATDirHandle::closedir() {
+    delete this;
+    return 0;
+}
+
+struct dirent *FATDirHandle::readdir() {
+    FILINFO finfo;
+#if _USE_LFN
+    static char lfn[_MAX_LFN * (_LFN_UNICODE ? 2 : 1) + 1];
+    finfo.lfname = lfn;
+    finfo.lfsize = sizeof(lfn);
+#endif
+    FRESULT res = f_readdir(&dir, &finfo);
+    if(res != 0 || finfo.fname[0]==0) {
+        return NULL;
+    } else {
+        char* fn;
+        int stringSize = 0;
+#if _USE_LFN
+        fn = *finfo.lfname ? finfo.lfname : finfo.fname;
+        stringSize = finfo.lfsize;
+#else
+        fn = fno.fname;
+        stringSize =  sizeof(finfo.fname);
+#endif
+        memcpy(cur_entry.d_name, fn, stringSize);
+        return &cur_entry;
+    }
+}
+
+void FATDirHandle::rewinddir() {
+    dir.index = 0;
+}
+
+off_t FATDirHandle::telldir() {
+    return dir.index;
+}
+
+void FATDirHandle::seekdir(off_t location) {
+    dir.index = location;
+}
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATDirHandle.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,31 @@
+/* mbed Microcontroller Library - FATDirHandle
+ * Copyright (c) 2008, sford
+ */
+
+#ifndef MBED_FATDIRHANDLE_H
+#define MBED_FATDIRHANDLE_H
+
+#include "DirHandle.h"
+#include "ff.h"
+
+namespace mbed {
+
+class FATDirHandle : public DirHandle {
+
+ public:
+    FATDirHandle(const DIR_t &the_dir);
+    virtual int closedir();
+    virtual struct dirent *readdir();
+    virtual void rewinddir();
+    virtual off_t telldir();
+    virtual void seekdir(off_t location);
+
+ private:
+    DIR_t dir;
+    struct dirent cur_entry;
+
+};
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATFileHandle.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,102 @@
+/* mbed Microcontroller Library - FATFileHandle
+ * Copyright (c) 2008, sford
+ */
+
+#include "FATFileHandle.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ff.h"
+#include "FATFileSystem.h"
+
+namespace mbed {
+
+#if FFSDEBUG_ENABLED
+static const char *FR_ERRORS[] = {
+    "FR_OK = 0", 
+    "FR_NOT_READY",          
+    "FR_NO_FILE",              
+    "FR_NO_PATH",             
+    "FR_INVALID_NAME",     
+    "FR_INVALID_DRIVE",      
+    "FR_DENIED",              
+    "FR_EXIST",              
+    "FR_RW_ERROR",          
+    "FR_WRITE_PROTECTED", 
+    "FR_NOT_ENABLED",    
+    "FR_NO_FILESYSTEM",    
+    "FR_INVALID_OBJECT",    
+    "FR_MKFS_ABORTED"    
+};
+#endif
+
+FATFileHandle::FATFileHandle(FIL_t fh) { 
+    _fh = fh;
+}
+    
+int FATFileHandle::close() {
+    FFSDEBUG("close\n");
+    int retval = f_close(&_fh);
+    delete this;
+    return retval;
+}
+
+ssize_t FATFileHandle::write(const void* buffer, size_t length) {
+    FFSDEBUG("write(%d)\n", length);
+    UINT n;
+    FRESULT res = f_write(&_fh, buffer, length, &n);
+    if(res) { 
+        FFSDEBUG("f_write() failed (%d, %s)", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return n;
+}
+        
+ssize_t FATFileHandle::read(void* buffer, size_t length) {
+    FFSDEBUG("read(%d)\n", length);
+    UINT n;
+    FRESULT res = f_read(&_fh, buffer, length, &n);
+    if(res) {
+        FFSDEBUG("f_read() failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return n;
+}
+        
+int FATFileHandle::isatty() {
+    return 0;
+}
+        
+off_t FATFileHandle::lseek(off_t position, int whence) {
+    FFSDEBUG("lseek(%i,%i)\n",position,whence);
+    if(whence == SEEK_END) {
+        position += _fh.fsize;
+    } else if(whence==SEEK_CUR) {
+        position += _fh.fptr;
+    }
+    FRESULT res = f_lseek(&_fh, position);
+    if(res) {
+        FFSDEBUG("lseek failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    } else {
+        FFSDEBUG("lseek OK, returning %i\n", _fh.fptr);
+        return _fh.fptr;
+    }
+}
+        
+int FATFileHandle::fsync() {
+    FFSDEBUG("fsync()\n");
+    FRESULT res = f_sync(&_fh);
+    if (res) {
+        FFSDEBUG("f_sync() failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return 0;
+}
+
+off_t FATFileHandle::flen() {
+    FFSDEBUG("flen\n");
+    return _fh.fsize;
+}
+
+} // namespace mbed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATFileHandle.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,33 @@
+/* mbed Microcontroller Library - FATFileHandle
+ * Copyright (c) 2008, sford
+ */
+
+#ifndef MBED_FATFILEHANDLE_H
+#define MBED_FATFILEHANDLE_H
+
+#include "FileHandle.h"
+#include "ff.h"
+
+namespace mbed {
+
+class FATFileHandle : public FileHandle {
+public:
+
+    FATFileHandle(FIL_t fh);
+    virtual int close();
+    virtual ssize_t write(const void* buffer, size_t length);
+    virtual ssize_t read(void* buffer, size_t length);
+    virtual int isatty();
+    virtual off_t lseek(off_t position, int whence);
+    virtual int fsync();
+    virtual off_t flen();
+
+protected:
+
+    FIL_t _fh;
+
+};
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATFileSystem.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,134 @@
+/* mbed Microcontroller Library - FATFileSystem
+ * Copyright (c) 2008, sford
+ */
+
+#include "FATFileSystem.h"
+
+#include "mbed.h"
+
+#include "FileSystemLike.h"
+#include "FATFileHandle.h"
+#include "FATDirHandle.h"
+#include "ff.h"
+//#include "Debug.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+DWORD get_fattime (void) {
+    return 999;
+}
+
+namespace mbed {
+
+#if FFSDEBUG_ENABLED
+static const char *FR_ERRORS[] = {
+    "FR_OK = 0", 
+    "FR_NOT_READY",          
+    "FR_NO_FILE",              
+    "FR_NO_PATH",             
+    "FR_INVALID_NAME",     
+    "FR_INVALID_DRIVE",      
+    "FR_DENIED",              
+    "FR_EXIST",              
+    "FR_RW_ERROR",          
+    "FR_WRITE_PROTECTED", 
+    "FR_NOT_ENABLED",    
+    "FR_NO_FILESYSTEM",    
+    "FR_INVALID_OBJECT",    
+    "FR_MKFS_ABORTED"    
+};
+#endif
+
+FATFileSystem *FATFileSystem::_ffs[_DRIVES] = {0};
+
+FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) {
+    FFSDEBUG("FATFileSystem(%s)\n", n);
+    for(int i=0; i<_DRIVES; i++) {
+        if(_ffs[i] == 0) {
+            _ffs[i] = this;
+            _fsid = i;
+            FFSDEBUG("Mounting [%s] on ffs drive [%d]\n", _name, _fsid);
+            f_mount(i, &_fs);
+            return;
+        }
+    }
+    error("Couldn't create %s in FATFileSystem::FATFileSystem\n",n);
+}
+    
+FATFileSystem::~FATFileSystem() {
+    for(int i=0; i<_DRIVES; i++) {
+        if(_ffs[i] == this) {
+            _ffs[i] = 0;
+            f_mount(i, NULL);
+        }
+    }
+}
+    
+FileHandle *FATFileSystem::open(const char* name, int flags) {
+    FFSDEBUG("open(%s) on filesystem [%s], drv [%d]\n", name, _name, _fsid);
+    char n[64];
+    sprintf(n, "%d:/%s", _fsid, name);
+
+    /* POSIX flags -> FatFS open mode */
+    BYTE openmode;
+    if(flags & O_RDWR) {
+        openmode = FA_READ|FA_WRITE;
+    } else if(flags & O_WRONLY) {
+        openmode = FA_WRITE;
+    } else {
+        openmode = FA_READ;
+    }
+    if(flags & O_CREAT) {
+        if(flags & O_TRUNC) {
+            openmode |= FA_CREATE_ALWAYS;
+        } else {
+            openmode |= FA_OPEN_ALWAYS;
+        }
+    }
+
+    FIL_t fh;
+    FRESULT res = f_open(&fh, n, openmode);
+    if(res) { 
+        FFSDEBUG("f_open('w') failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return NULL;
+    }
+    if(flags & O_APPEND) {
+        f_lseek(&fh, fh.fsize);
+    }
+    return new FATFileHandle(fh);
+}
+    
+int FATFileSystem::remove(const char *filename) {
+    FRESULT res = f_unlink(filename);
+    if(res) { 
+        FFSDEBUG("f_unlink() failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return 0;
+}
+
+int FATFileSystem::format() {
+    FFSDEBUG("format()\n");
+    FRESULT res = f_mkfs(_fsid, 0, 512); // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
+    if(res) {
+        FFSDEBUG("f_mkfs() failed (%d, %s)\n", res, FR_ERRORS[res]);
+        return -1;
+    }
+    return 0;
+}
+
+DirHandle *FATFileSystem::opendir(const char *name) {
+    DIR_t dir;
+    FRESULT res = f_opendir(&dir, name);
+    if(res != 0) {
+        return NULL;
+    }
+    return new FATDirHandle(dir);
+}
+
+int FATFileSystem::mkdir(const char *name, mode_t mode) {
+    FRESULT res = f_mkdir(name);
+    return res == 0 ? 0 : -1;
+}
+
+} // namespace mbed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFS/FATFileSystem.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,61 @@
+/* mbed Microcontroller Library - FATFileSystem
+ * Copyright (c) 2008, sford
+ */
+
+/* Library: FATFileSystem.h
+ * A library of stuff to make a fat filesystem on top of a block device
+ */
+
+#ifndef MBED_FATFILESYSTEM_H
+#define MBED_FATFILESYSTEM_H
+
+#ifndef FFSDEBUG_ENABLED
+#define FFSDEBUG_ENABLED 0
+#endif
+
+#if FFSDEBUG_ENABLED
+#define FFSDEBUG(FMT, ...) printf(FMT, ##__VA_ARGS__)
+#else
+#define FFSDEBUG(FMT, ...)
+#endif
+
+#include "FileSystemLike.h"
+#include "FileHandle.h"
+#include "ff.h"
+#include "diskio.h"
+
+namespace mbed {
+/* Class: FATFileSystem
+ * The class itself
+ */
+class FATFileSystem : public FileSystemLike {
+public:
+
+    FATFileSystem(const char* n);
+    virtual ~FATFileSystem();
+    
+    /* Function: open
+       * open a file on the filesystem. never called directly
+       */
+    virtual FileHandle *open(const char* name, int flags);
+    virtual int remove(const char *filename);
+    virtual int format();
+        virtual DirHandle *opendir(const char *name);
+        virtual int mkdir(const char *name, mode_t mode);
+    
+    FATFS _fs;                                // Work area (file system object) for logical drive    
+    static FATFileSystem *_ffs[_DRIVES];    // FATFileSystem objects, as parallel to FatFs drives array
+    int _fsid;
+    
+    virtual int disk_initialize() { return 0; }
+    virtual int disk_status() { return 0; }
+    virtual int disk_read(char *buffer, int sector) = 0;
+    virtual int disk_write(const char *buffer, int sector) = 0;
+    virtual int disk_sync() { return 0; }
+    virtual int disk_sectors() = 0;
+     
+};
+    
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFSSD/SDFileSystem.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,457 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already 
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of: 
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will 
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and 
+ * indirectly determine whether it is a version 1.x SD/non-SD card or 
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ * 
+ * The protocol supports a CRC, but by default it is off (except for the 
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think! 
+ * 
+ * Standard capacity cards have variable data block sizes, whereas High 
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks 
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then 
+ * a data token or an error.
+ * 
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising 
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte 
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *  
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] | 
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+ 
+#include "SDFileSystem.h"
+
+#define SD_COMMAND_TIMEOUT 5000
+
+SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
+  FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs) {
+      _cs = 1; 
+}
+
+#define R1_IDLE_STATE           (1 << 0)
+#define R1_ERASE_RESET          (1 << 1)
+#define R1_ILLEGAL_COMMAND      (1 << 2)
+#define R1_COM_CRC_ERROR        (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR        (1 << 5)
+#define R1_PARAMETER_ERROR      (1 << 6)
+
+// Types
+//  - v1.x Standard Capacity
+//  - v2.x Standard Capacity
+//  - v2.x High Capacity
+//  - Not recognised as an SD Card
+
+#define SDCARD_FAIL 0
+#define SDCARD_V1   1
+#define SDCARD_V2   2
+#define SDCARD_V2HC 3
+
+int SDFileSystem::initialise_card() {
+    // Set to 100kHz for initialisation, and clock card with cs = 1
+    _spi.frequency(100000); 
+    _cs = 1;
+    for(int i=0; i<16; i++) {   
+        _spi.write(0xFF);
+    }
+
+    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+    if(_cmd(0, 0) != R1_IDLE_STATE) { 
+        fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
+        return SDCARD_FAIL;
+    }
+
+    // send CMD8 to determine whther it is ver 2.x
+    int r = _cmd8();
+    if(r == R1_IDLE_STATE) {
+        return initialise_card_v2();
+    } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+        return initialise_card_v1();
+    } else {
+        fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
+        return SDCARD_FAIL;
+    }
+}
+
+int SDFileSystem::initialise_card_v1() {
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            return SDCARD_V1;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v1.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::initialise_card_v2() {
+    
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            _cmd58();
+            return SDCARD_V2;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v2.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::disk_initialize() {
+
+    int i = initialise_card();
+//    printf("init card = %d\n", i);
+//    printf("OK\n");
+
+    _sectors = _sd_sectors();
+
+    // Set block length to 512 (CMD16)
+    if(_cmd(16, 512) != 0) {
+        fprintf(stderr, "Set 512-byte block timed out\n");
+        return 1;
+    }
+        
+    _spi.frequency(1000000); // Set to 1MHz for data transfer
+    return 0;
+}
+
+int SDFileSystem::disk_write(const char *buffer, int block_number) {
+    // set write address for single block (CMD24)
+    if(_cmd(24, block_number * 512) != 0) {
+        return 1;
+    }
+
+    // send the data block
+    _write(buffer, 512);    
+    return 0;    
+}
+
+int SDFileSystem::disk_read(char *buffer, int block_number) {        
+    // set read address for single block (CMD17)
+    if(_cmd(17, block_number * 512) != 0) {
+        return 1;
+    }
+    
+    // receive the data
+    _read(buffer, 512);
+    return 0;
+}
+
+int SDFileSystem::disk_status() { return 0; }
+int SDFileSystem::disk_sync() { return 0; }
+int SDFileSystem::disk_sectors() { return _sectors; }
+
+// PRIVATE FUNCTIONS
+
+int SDFileSystem::_cmd(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+int SDFileSystem::_cmdx(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+
+int SDFileSystem::_cmd58() {
+    _cs = 0; 
+    int arg = 0;
+    
+    // send a command
+    _spi.write(0x40 | 58);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            int ocr = _spi.write(0xFF) << 24;
+            ocr |= _spi.write(0xFF) << 16;
+            ocr |= _spi.write(0xFF) << 8;
+            ocr |= _spi.write(0xFF) << 0;
+//            printf("OCR = 0x%08X\n", ocr);
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_cmd8() {
+    _cs = 0; 
+    
+    // send a command
+    _spi.write(0x40 | 8); // CMD8
+    _spi.write(0x00);     // reserved
+    _spi.write(0x00);     // reserved
+    _spi.write(0x01);     // 3.3v
+    _spi.write(0xAA);     // check pattern
+    _spi.write(0x87);     // crc
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) {
+        char response[5];
+        response[0] = _spi.write(0xFF);
+        if(!(response[0] & 0x80)) {
+                for(int j=1; j<5; j++) {
+                    response[i] = _spi.write(0xFF);
+                }
+                _cs = 1;
+                _spi.write(0xFF);
+                return response[0];
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_read(char *buffer, int length) {
+    _cs = 0;
+
+    // read until start byte (0xFF)
+    while(_spi.write(0xFF) != 0xFE);
+
+    // read data
+    for(int i=0; i<length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+
+    _cs = 1;    
+    _spi.write(0xFF);
+    return 0;
+}
+
+int SDFileSystem::_write(const char *buffer, int length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for(int i=0; i<length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF); 
+    _spi.write(0xFF);
+
+    // check the repsonse token
+    if((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1;
+        _spi.write(0xFF);        
+        return 1;
+    }
+
+    // wait for write to finish
+    while(_spi.write(0xFF) == 0);
+
+    _cs = 1; 
+    _spi.write(0xFF);
+    return 0;
+}
+
+static int ext_bits(char *data, int msb, int lsb) {
+    int bits = 0;
+    int size = 1 + msb - lsb; 
+    for(int i=0; i<size; i++) {
+        int position = lsb + i;
+        int byte = 15 - (position >> 3);
+        int bit = position & 0x7;
+        int value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+int SDFileSystem::_sd_sectors() {
+
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if(_cmdx(9, 0) != 0) {
+        fprintf(stderr, "Didn't get a response from the disk\n");
+        return 0;
+    }
+    
+    char csd[16];    
+    if(_read(csd, 16) != 0) {
+        fprintf(stderr, "Couldn't read csd response from disk\n");
+        return 0;
+    }
+
+    // csd_structure : csd[127:126]
+    // c_size        : csd[73:62]
+    // c_size_mult   : csd[49:47]
+    // read_bl_len   : csd[83:80] - the *maximum* read block length
+
+    int csd_structure = ext_bits(csd, 127, 126);
+    int c_size = ext_bits(csd, 73, 62);
+    int c_size_mult = ext_bits(csd, 49, 47);
+    int read_bl_len = ext_bits(csd, 83, 80);
+
+//    printf("CSD_STRUCT = %d\n", csd_structure);
+    
+    if(csd_structure != 0) {
+        fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
+        return 0;
+    }
+             
+    // memory capacity = BLOCKNR * BLOCK_LEN
+    // where
+    //  BLOCKNR = (C_SIZE+1) * MULT
+    //  MULT = 2^(C_SIZE_MULT+2) (C_SIZE_MULT < 8)
+    //  BLOCK_LEN = 2^READ_BL_LEN, (READ_BL_LEN < 12)         
+                            
+    int block_len = 1 << read_bl_len;
+    int mult = 1 << (c_size_mult + 2);
+    int blocknr = (c_size + 1) * mult;
+    int capacity = blocknr * block_len;
+        
+    int blocks = capacity / 512;
+        
+    return blocks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChaNFSSD/SDFileSystem.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,81 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MBED_SDFILESYSTEM_H
+#define MBED_SDFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+
+/** Access the filesystem on an SD Card using SPI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "SDFileSystem.h"
+ *
+ * SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs
+ *  
+ * int main() {
+ *     FILE *fp = fopen("/sd/myfile.txt", "w");
+ *     fprintf(fp, "Hello World!\n");
+ *     fclose(fp);
+ * }
+ */
+class SDFileSystem : public FATFileSystem {
+public:
+
+    /** Create the File System for accessing an SD Card using SPI
+     *
+     * @param mosi SPI mosi pin connected to SD Card
+     * @param miso SPI miso pin conencted to SD Card
+     * @param sclk SPI sclk pin connected to SD Card
+     * @param cs   DigitalOut pin used as SD Card chip select
+     * @param name The name used to access the virtual filesystem
+     */
+    SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
+    virtual int disk_initialize();
+    virtual int disk_write(const char *buffer, int block_number);
+    virtual int disk_read(char *buffer, int block_number);    
+    virtual int disk_status();
+    virtual int disk_sync();
+    virtual int disk_sectors();
+
+protected:
+
+    int _cmd(int cmd, int arg);
+    int _cmdx(int cmd, int arg);
+    int _cmd8();
+    int _cmd58();
+    int initialise_card();
+    int initialise_card_v1();
+    int initialise_card_v2();
+    
+    int _read(char *buffer, int length);
+    int _write(const char *buffer, int length);
+    int _sd_sectors();
+    int _sectors;
+    
+    SPI _spi;
+    DigitalOut _cs;     
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/fatfilesystem/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBBusInterface.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,61 @@
+/* USBBusInterface.h */
+/* USB Bus Interface */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USBBUSINTERFACE_H
+#define USBBUSINTERFACE_H
+
+#include "mbed.h"
+#include "USBEndpoints.h"
+
+class USBHAL {
+public:
+    /* Configuration */
+    USBHAL();
+    ~USBHAL();
+    void connect(void);
+    void disconnect(void);
+    void configureDevice(void);
+    void unconfigureDevice(void);
+    void setAddress(uint8_t address);
+    void remoteWakeup(void);
+
+    /* Endpoint 0 */
+    void EP0setup(uint8_t *buffer);
+    void EP0read(void);
+    uint32_t EP0getReadResult(uint8_t *buffer);
+    void EP0write(uint8_t *buffer, uint32_t size);
+    void EP0getWriteResult(void);
+    void EP0stall(void);
+
+    /* Other endpoints */
+    EP_STATUS endpointRead(uint8_t endpoint, uint32_t maximumSize);
+    EP_STATUS endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead);
+    EP_STATUS endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size);
+    EP_STATUS endpointWriteResult(uint8_t endpoint);
+    void stallEndpoint(uint8_t endpoint);
+    void unstallEndpoint(uint8_t endpoint);
+    bool realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options);
+    bool getEndpointStallState(unsigned char endpoint);
+    
+    void NakIntEnable(int frameNumber);
+    
+protected:
+    virtual void busReset(void){};
+    virtual void EP0setupCallback(void){};
+    virtual void EP0out(void){};
+    virtual void EP0in(void){};
+    virtual void connectStateChanged(unsigned int connected){};
+    virtual void suspendStateChanged(unsigned int suspended){};
+    void SOF(int frameNumber){};
+    virtual bool EPBULK_OUT_callback(){return false;};
+    virtual bool EPBULK_IN_callback(){return false;};
+    
+private:
+    void usbisr(void);
+    static void _usbisr(void);
+    static USBHAL * instance;
+};
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBBusInterface_LPC11U.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,660 @@
+// USBBusInterface_LPC11U.c
+// USB Bus Interface for NXP LPC11Uxx
+// Copyright (c) 2011 ARM Limited. All rights reserved.
+
+// Reference:
+// NXP UM10462 LPC11U1x User manual Rev. 1 &#65533; 14 April 2011
+
+#ifdef TARGET_LPC11U24
+
+#include "USBBusInterface.h"
+
+USBHAL * USBHAL::instance;
+
+
+// Valid physical endpoint numbers are 0 to (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
+#define LAST_PHYSICAL_ENDPOINT (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
+
+// Convert physical endpoint number to register bit
+#define EP(endpoint) (1UL<<endpoint)
+
+// Convert physical to logical
+#define PHY_TO_LOG(endpoint)    ((endpoint)>>1)
+
+// Get endpoint direction
+#define IN_EP(endpoint)     ((endpoint) & 1U ? true : false)
+#define OUT_EP(endpoint)    ((endpoint) & 1U ? false : true)
+
+// USB RAM
+#define USB_RAM_START (0x20004000)
+#define USB_RAM_SIZE  (0x00000800)
+
+// SYSAHBCLKCTRL
+#define CLK_USB     (1UL<<14)
+#define CLK_USBRAM  (1UL<<27)
+
+// USB Information register
+#define FRAME_NR(a)     ((a) & 0x7ff)   // Frame number
+
+// USB Device Command/Status register
+#define DEV_ADDR_MASK   (0x7f)          // Device address
+#define DEV_ADDR(a)     ((a) & DEV_ADDR_MASK)
+#define DEV_EN          (1UL<<7)        // Device enable
+#define SETUP           (1UL<<8)        // SETUP token received
+#define PLL_ON          (1UL<<9)        // PLL enabled in suspend
+#define DCON            (1UL<<16)       // Device status - connect
+#define DSUS            (1UL<<17)       // Device status - suspend
+#define DCON_C          (1UL<<24)       // Connect change
+#define DSUS_C          (1UL<<25)       // Suspend change
+#define DRES_C          (1UL<<26)       // Reset change
+#define VBUSDEBOUNCED   (1UL<<28)       // Vbus detected
+
+// Endpoint Command/Status list
+#define CMDSTS_A                 (1UL<<31)          // Active
+#define CMDSTS_D                 (1UL<<30)          // Disable
+#define CMDSTS_S                 (1UL<<29)          // Stall
+#define CMDSTS_TR                (1UL<<28)          // Toggle Reset
+#define CMDSTS_RF                (1UL<<27)          // Rate Feedback mode
+#define CMDSTS_TV                (1UL<<27)          // Toggle Value
+#define CMDSTS_T                 (1UL<<26)          // Endpoint Type
+#define CMDSTS_NBYTES(n)         (((n)&0x3ff)<<16)  // Number of bytes
+#define CMDSTS_ADDRESS_OFFSET(a) (((a)>>6)&0xffff)  // Buffer start address
+
+#define BYTES_REMAINING(s)       (((s)>>16)&0x3ff)  // Bytes remaining after transfer
+
+// USB Non-endpoint interrupt sources
+#define FRAME_INT   (1UL<<30)
+#define DEV_INT     (1UL<<31)
+
+static int epComplete = 0;
+
+// One entry for a double-buffered logical endpoint in the endpoint
+// command/status list. Endpoint 0 is single buffered, out[1] is used
+// for the SETUP packet and in[1] is not used
+typedef __packed struct {
+    uint32_t out[2];
+    uint32_t in[2];
+} EP_COMMAND_STATUS;
+
+typedef __packed struct {
+    uint8_t out[MAX_PACKET_SIZE_EP0];
+    uint8_t in[MAX_PACKET_SIZE_EP0];
+    uint8_t setup[SETUP_PACKET_SIZE];
+} CONTROL_TRANSFER;
+
+typedef __packed struct {
+    uint32_t    maxPacket;
+    uint32_t    buffer[2];
+    uint32_t    options;
+} EP_STATE;
+
+static volatile EP_STATE endpointState[NUMBER_OF_PHYSICAL_ENDPOINTS];
+
+// Pointer to the endpoint command/status list
+static EP_COMMAND_STATUS *ep = NULL;
+
+// Pointer to endpoint 0 data (IN/OUT and SETUP)
+static CONTROL_TRANSFER *ct = NULL;
+
+// Shadow DEVCMDSTAT register to avoid accidentally clearing flags or
+// initiating a remote wakeup event.
+static volatile uint32_t devCmdStat;
+
+// Pointers used to allocate USB RAM
+static uint32_t usbRamPtr = USB_RAM_START;
+static uint32_t epRamPtr = 0; // Buffers for endpoints > 0 start here
+
+#define ROUND_UP_TO_MULTIPLE(x, m) ((((x)+((m)-1))/(m))*(m))
+
+void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size);
+void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size) {
+    if (size > 0) {
+        do {
+            *dst++ = *src++;
+        } while (--size > 0);
+    }
+}
+
+
+USBHAL::USBHAL(void) {
+    NVIC_DisableIRQ(USB_IRQn);
+
+    // USB_VBUS input, Pull down, Hysteresis enabled
+    //LPC_IOCON->PIO0_3 = 0x00000029;
+    // nUSB_CONNECT output
+    LPC_IOCON->PIO0_6 = 0x00000001;
+
+    // Enable clocks (USB registers, USB RAM)
+    LPC_SYSCON->SYSAHBCLKCTRL |= CLK_USB | CLK_USBRAM;
+
+    // Ensure device disconnected (DCON not set)
+    LPC_USB->DEVCMDSTAT = 0;
+
+    // Device must be disconnected for at least 2.5uS
+    // to ensure that the USB host sees the device as
+    // disconnected if the target CPU is reset.
+    wait(0.3);
+
+
+    // Reserve space in USB RAM for endpoint command/status list
+    // Must be 256 byte aligned
+    usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 256);
+    ep = (EP_COMMAND_STATUS *)usbRamPtr;
+    usbRamPtr += (sizeof(EP_COMMAND_STATUS) * NUMBER_OF_LOGICAL_ENDPOINTS);
+    LPC_USB->EPLISTSTART = (uint32_t)(ep) & 0xffffff00;
+
+    // Reserve space in USB RAM for Endpoint 0
+    // Must be 64 byte aligned
+    usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 64);
+    ct = (CONTROL_TRANSFER *)usbRamPtr;
+    usbRamPtr += sizeof(CONTROL_TRANSFER);
+    LPC_USB->DATABUFSTART =(uint32_t)(ct) & 0xffc00000;
+
+    // Setup command/status list for EP0
+    ep[0].out[0] = 0;
+    ep[0].in[0] =  0;
+    ep[0].out[1] = CMDSTS_ADDRESS_OFFSET((uint32_t)ct->setup);
+
+    // Route all interrupts to IRQ, some can be routed to
+    // USB_FIQ if you wish.
+    LPC_USB->INTROUTING = 0;
+
+    // Set device address 0, enable USB device, no remote wakeup
+    devCmdStat = DEV_ADDR(0) | DEV_EN | DSUS;
+    LPC_USB->DEVCMDSTAT = devCmdStat;
+
+    // Enable interrupts for device events and EP0
+    LPC_USB->INTEN = DEV_INT | EP(EP0IN) | EP(EP0OUT);
+    instance = this;
+    NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
+    NVIC_EnableIRQ(USB_IRQn);
+}
+
+USBHAL::~USBHAL(void) {
+    // Ensure device disconnected (DCON not set)
+    LPC_USB->DEVCMDSTAT = 0;
+
+    // Disable USB interrupts
+    NVIC_DisableIRQ(USB_IRQn);
+}
+
+void USBHAL::connect(void) {
+    devCmdStat |= DCON;
+    LPC_USB->DEVCMDSTAT = devCmdStat;
+}
+
+void USBHAL::disconnect(void) {
+    devCmdStat &= ~DCON;
+    LPC_USB->DEVCMDSTAT = devCmdStat;
+}
+
+void USBHAL::configureDevice(void) {
+}
+
+void USBHAL::unconfigureDevice(void) {
+}
+
+void USBHAL::EP0setup(uint8_t *buffer) {
+    // Copy setup packet data
+    USBMemCopy(buffer, ct->setup, SETUP_PACKET_SIZE);
+}
+
+void USBHAL::EP0read(void) {
+    // Start an endpoint 0 read
+
+    // The USB ISR will call USBDevice_EP0out() when a packet has been read,
+    // the USBDevice layer then calls USBBusInterface_EP0getReadResult() to
+    // read the data.
+
+    ep[0].out[0] = CMDSTS_A |CMDSTS_NBYTES(MAX_PACKET_SIZE_EP0) \
+            | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out);
+}
+
+uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
+    // Complete an endpoint 0 read
+    uint32_t bytesRead;
+
+    // Find how many bytes were read
+    bytesRead = MAX_PACKET_SIZE_EP0 - BYTES_REMAINING(ep[0].out[0]);
+
+    // Copy data
+    USBMemCopy(buffer, ct->out, bytesRead);
+    return bytesRead;
+}
+
+void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
+    // Start and endpoint 0 write
+
+    // The USB ISR will call USBDevice_EP0in() when the data has
+    // been written, the USBDevice layer then calls
+    // USBBusInterface_EP0getWriteResult() to complete the transaction.
+
+    // Copy data
+    USBMemCopy(ct->in, buffer, size);
+
+    // Start transfer
+    ep[0].in[0] = CMDSTS_A | CMDSTS_NBYTES(size) \
+            | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->in);
+}
+
+
+EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
+    ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_A | CMDSTS_NBYTES(maximumSize) \
+            | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out);
+    return EP_PENDING;
+}
+
+EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) {
+    if (!(epComplete & EP(endpoint)))
+        return EP_PENDING;
+    else {
+        epComplete &= ~EP(endpoint);
+        // Find how many bytes were read
+        *bytesRead = (uint32_t) (endpointState[endpoint].maxPacket - BYTES_REMAINING(ep[PHY_TO_LOG(endpoint)].out[0]));
+        // Copy data
+        USBMemCopy(data, ct->out, *bytesRead);
+        return EP_COMPLETED;
+    }
+}
+
+void USBHAL::EP0getWriteResult(void) {
+    // Complete an endpoint 0 write
+
+    // Nothing required for this target
+    return;
+}
+
+void USBHAL::EP0stall(void) {
+    ep[0].in[0] = CMDSTS_S;
+    ep[0].out[0] = CMDSTS_S;
+}
+
+void USBHAL::setAddress(uint8_t address) {
+    devCmdStat &= ~DEV_ADDR_MASK;
+    devCmdStat |= DEV_ADDR(address);
+    LPC_USB->DEVCMDSTAT = devCmdStat;
+}
+
+EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
+    uint32_t flags = 0;
+    uint32_t bf;
+
+    // Validate parameters
+    if (data == NULL) {
+        return EP_INVALID;
+    }
+
+    if (endpoint > LAST_PHYSICAL_ENDPOINT) {
+        return EP_INVALID;
+    }
+
+    if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
+        return EP_INVALID;
+    }
+
+    if (size > endpointState[endpoint].maxPacket) {
+        return EP_INVALID;
+    }
+
+    if (LPC_USB->EPBUFCFG & EP(endpoint)) {
+        // Double buffered  // TODO: FIX THIS
+        if (LPC_USB->EPINUSE & EP(endpoint)) {
+            bf = 1;
+        } else {
+            bf = 0;
+        }
+    } else {
+        // Single buffered
+        bf = 0;
+    }
+
+    // Check if already active
+    if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
+        return EP_INVALID;
+    }
+
+    // Check if stalled
+    if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
+        return EP_STALLED;
+    }
+
+    // Copy data to USB RAM
+    USBMemCopy((uint8_t *)endpointState[endpoint].buffer[bf], data, size);
+
+    // Add options
+    if (endpointState[endpoint].options & RATE_FEEDBACK_MODE) {
+        flags |= CMDSTS_RF;
+    }
+
+    if (endpointState[endpoint].options & ISOCHRONOUS) {
+        flags |= CMDSTS_T;
+    }
+
+    // Add transfer
+    ep[PHY_TO_LOG(endpoint)].in[bf] = CMDSTS_ADDRESS_OFFSET( \
+            endpointState[endpoint].buffer[bf]) \
+            | CMDSTS_NBYTES(size) | CMDSTS_A | flags;
+
+    return EP_PENDING;
+}
+
+EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
+    uint32_t bf;
+    // Validate parameters
+
+    if (endpoint > LAST_PHYSICAL_ENDPOINT) {
+        return EP_INVALID;
+    }
+
+    if (OUT_EP(endpoint)) {
+        return EP_INVALID;
+    }
+
+    if (LPC_USB->EPBUFCFG & EP(endpoint)) {
+        // Double buffered     // TODO: FIX THIS
+        if (LPC_USB->EPINUSE & EP(endpoint)) {
+            bf = 1;
+        } else {
+            bf = 0;
+        }
+    } else {
+        // Single buffered
+        bf = 0;
+    }
+
+    // Check if endpoint still active
+    if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
+        return EP_PENDING;
+    }
+
+    // Check if stalled
+    if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
+        return EP_STALLED;
+    }
+
+    return EP_COMPLETED;
+}
+
+void USBHAL::stallEndpoint(uint8_t endpoint) {
+
+    // TODO: should this clear active bit?
+
+    if (IN_EP(endpoint)) {
+        ep[PHY_TO_LOG(endpoint)].in[0] |= CMDSTS_S;
+        ep[PHY_TO_LOG(endpoint)].in[1] |= CMDSTS_S;
+    } else {
+        ep[PHY_TO_LOG(endpoint)].out[0] |= CMDSTS_S;
+        ep[PHY_TO_LOG(endpoint)].out[1] |= CMDSTS_S;
+    }
+}
+
+void USBHAL::unstallEndpoint(uint8_t endpoint) {
+    if (LPC_USB->EPBUFCFG & EP(endpoint)) {
+        // Double buffered
+        if (IN_EP(endpoint)) {
+            ep[PHY_TO_LOG(endpoint)].in[0] = 0; // S = 0
+            ep[PHY_TO_LOG(endpoint)].in[1] = 0; // S = 0
+
+            if (LPC_USB->EPINUSE & EP(endpoint)) {
+                ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
+            } else {
+                ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
+            }
+        } else {
+            ep[PHY_TO_LOG(endpoint)].out[0] = 0; // S = 0
+            ep[PHY_TO_LOG(endpoint)].out[1] = 0; // S = 0
+
+            if (LPC_USB->EPINUSE & EP(endpoint)) {
+                ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
+            } else {
+                ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
+            }
+        }
+    } else {
+        // Single buffered
+        if (IN_EP(endpoint)) {
+            ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
+        } else {
+            ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
+        }
+    }
+}
+
+bool USBHAL::getEndpointStallState(unsigned char endpoint) {
+    if (IN_EP(endpoint)) {
+        if (LPC_USB->EPINUSE & EP(endpoint)) {
+            if (ep[PHY_TO_LOG(endpoint)].in[1] & CMDSTS_S) {
+                return true;
+            }
+        } else {
+            if (ep[PHY_TO_LOG(endpoint)].in[0] & CMDSTS_S) {
+                return true;
+            }
+        }
+    } else {
+        if (LPC_USB->EPINUSE & EP(endpoint)) {
+            if (ep[PHY_TO_LOG(endpoint)].out[1] & CMDSTS_S) {
+                return true;
+            }
+        } else {
+            if (ep[PHY_TO_LOG(endpoint)].out[0] & CMDSTS_S) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) {
+    uint32_t tmpEpRamPtr;
+
+    //  Support for double buffered endpoints needs to be fixed/finished in this
+    //  software - force single buffered for now.
+
+
+    options |= SINGLE_BUFFERED; // TODO - FIX THIS
+
+    if (endpoint > LAST_PHYSICAL_ENDPOINT) {
+        return false;
+    }
+
+    // Not applicable to the control endpoints
+    if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
+        return false;
+    }
+
+    // Allocate buffers in USB RAM
+    tmpEpRamPtr = epRamPtr;
+
+    // Must be 64 byte aligned
+    tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
+
+    if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
+        // Out of memory
+        return false;
+    }
+
+    // Allocate first buffer
+    endpointState[endpoint].buffer[0] = tmpEpRamPtr;
+    tmpEpRamPtr += maxPacket;
+
+    if (!(options & SINGLE_BUFFERED)) {
+        // Must be 64 byte aligned
+        tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
+
+        if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
+            // Out of memory
+            return false;
+        }
+
+        // Allocate second buffer
+        endpointState[endpoint].buffer[1] = tmpEpRamPtr;
+        tmpEpRamPtr += maxPacket;
+    }
+
+    // Commit to this USB RAM allocation
+    epRamPtr = tmpEpRamPtr;
+
+    // Remaining endpoint state values
+    endpointState[endpoint].maxPacket = maxPacket;
+    endpointState[endpoint].options = options;
+
+    // Enable double buffering if required
+    if (options & SINGLE_BUFFERED) {
+        LPC_USB->EPBUFCFG &= ~EP(endpoint);
+    } else {
+        // Double buffered
+        LPC_USB->EPBUFCFG |= EP(endpoint);
+    }
+
+    // Enable interrupt for OUT endpoint
+    LPC_USB->INTEN |= EP(endpoint);
+
+    // Enable endpoint
+    unstallEndpoint(endpoint);
+    return true;
+}
+
+void USBHAL::remoteWakeup(void) {
+    // Clearing DSUS bit initiates a remote wakeup if the
+    // device is currently enabled and suspended - otherwise
+    // it has no effect.
+    LPC_USB->DEVCMDSTAT = devCmdStat & ~DSUS;
+}
+
+
+static void disableEndpoints(void) {
+    uint32_t logEp;
+
+    // Ref. Table 158 "When a bus reset is received, software
+    // must set the disable bit of all endpoints to 1".
+
+    for (logEp = 1; logEp < NUMBER_OF_LOGICAL_ENDPOINTS; logEp++) {
+        ep[logEp].out[0] = CMDSTS_D;
+        ep[logEp].out[1] = CMDSTS_D;
+        ep[logEp].in[0] =  CMDSTS_D;
+        ep[logEp].in[1] =  CMDSTS_D;
+    }
+
+    // Start of USB RAM for endpoints > 0
+    epRamPtr = usbRamPtr;
+}
+
+
+
+void USBHAL::_usbisr(void)
+{
+    instance->usbisr();
+}
+
+
+void USBHAL::usbisr(void) {
+    // Start of frame
+    if (LPC_USB->INTSTAT & FRAME_INT) {
+        // Clear SOF interrupt
+        LPC_USB->INTSTAT = FRAME_INT;
+
+        // SOF event, read frame number
+        SOF(FRAME_NR(LPC_USB->INFO));
+    }
+
+    // Device state
+    if (LPC_USB->INTSTAT & DEV_INT) {
+        LPC_USB->INTSTAT = DEV_INT;
+
+        if (LPC_USB->DEVCMDSTAT & DCON_C) {
+            // Connect status changed
+            LPC_USB->DEVCMDSTAT = devCmdStat | DCON_C;
+
+            connectStateChanged((LPC_USB->DEVCMDSTAT & DCON) != 0);
+        }
+
+        if (LPC_USB->DEVCMDSTAT & DSUS_C) {
+            // Suspend status changed
+            LPC_USB->DEVCMDSTAT = devCmdStat | DSUS_C;
+
+            suspendStateChanged((LPC_USB->DEVCMDSTAT & DSUS) != 0);
+        }
+
+        if (LPC_USB->DEVCMDSTAT & DRES_C) {
+            // Bus reset
+            LPC_USB->DEVCMDSTAT = devCmdStat | DRES_C;
+
+            // Disable endpoints > 0
+            disableEndpoints();
+
+            // Bus reset event
+            busReset();
+        }
+    }
+
+    // Endpoint 0
+    if (LPC_USB->INTSTAT & EP(EP0OUT)) {
+        // Clear EP0OUT/SETUP interrupt
+        LPC_USB->INTSTAT = EP(EP0OUT);
+
+        // Check if SETUP
+        if (LPC_USB->DEVCMDSTAT & SETUP) {
+            // Clear Active and Stall bits for EP0
+            // Documentation does not make it clear if we must use the
+            // EPSKIP register to achieve this, Fig. 16 and NXP reference
+            // code suggests we can just clear the Active bits - check with
+            // NXP to be sure.
+            ep[0].in[0] = 0;
+            ep[0].out[0] = 0;
+
+            // Clear EP0IN interrupt
+            LPC_USB->INTSTAT = EP(EP0IN);
+
+            // Clear SETUP (and INTONNAK_CI/O) in device status register
+            LPC_USB->DEVCMDSTAT = devCmdStat | SETUP;
+
+            // EP0 SETUP event (SETUP data received)
+            EP0setupCallback();
+        } else {
+            // EP0OUT ACK event (OUT data received)
+            EP0out();
+        }
+    }
+
+    if (LPC_USB->INTSTAT & EP(EP0IN)) {
+        // Clear EP0IN interrupt
+        LPC_USB->INTSTAT = EP(EP0IN);
+
+        // EP0IN ACK event (IN data sent)
+        EP0in();
+    }
+
+    if (LPC_USB->INTSTAT & EP(EP1IN)) {
+        // Clear EP1IN interrupt
+        LPC_USB->INTSTAT = EP(EP1IN);
+        epComplete |= EP(EP1IN);
+    }
+
+    if (LPC_USB->INTSTAT & EP(EP1OUT)) {
+        // Clear EP1OUT interrupt
+        LPC_USB->INTSTAT = EP(EP1OUT);
+        epComplete |= EP(EP1OUT);
+    }
+
+    if (LPC_USB->INTSTAT & EP(EPBULK_IN)) {
+        // Clear EPBULK_OUT interrupt
+        LPC_USB->INTSTAT = EP(EPBULK_IN);
+        epComplete |= EP(EPBULK_IN);
+        if(EPBULK_IN_callback())
+            epComplete &= ~EP(EPBULK_IN);
+    }
+
+    if (LPC_USB->INTSTAT & EP(EPBULK_OUT)) {
+        // Clear EPBULK_OUT interrupt
+        LPC_USB->INTSTAT = EP(EPBULK_OUT);
+        epComplete |= EP(EPBULK_OUT);
+        //Call callback function. If true, clear epComplete
+        if(EPBULK_OUT_callback())
+            epComplete &= ~EP(EPBULK_OUT);
+    }
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBBusInterface_LPC17_LPC23.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,681 @@
+// USBBusInterface_LPC17_LPC23.c
+// USB Bus Interface for NXP LPC1768 and LPC2368
+// Copyright (c) 2011 ARM Limited. All rights reserved.
+
+#ifdef TARGET_LPC1768
+
+//#define DEBUG
+#include "dbg.h"
+#include "USBBusInterface.h"
+
+
+// Get endpoint direction
+#define IN_EP(endpoint)     ((endpoint) & 1U ? true : false)
+#define OUT_EP(endpoint)    ((endpoint) & 1U ? false : true)
+
+// Convert physical endpoint number to register bit
+#define EP(endpoint) (1UL<<endpoint)
+
+// Power Control for Peripherals register
+#define PCUSB      (1UL<<31)
+
+// USB Clock Control register
+#define DEV_CLK_EN (1UL<<1)
+#define AHB_CLK_EN (1UL<<4)
+
+// USB Clock Status register
+#define DEV_CLK_ON (1UL<<1)
+#define AHB_CLK_ON (1UL<<4)
+
+// USB Device Interupt registers
+#define FRAME      (1UL<<0)
+#define EP_FAST    (1UL<<1)
+#define EP_SLOW    (1UL<<2)
+#define DEV_STAT   (1UL<<3)
+#define CCEMPTY    (1UL<<4)
+#define CDFULL     (1UL<<5)
+#define RxENDPKT   (1UL<<6)
+#define TxENDPKT   (1UL<<7)
+#define EP_RLZED   (1UL<<8)
+#define ERR_INT    (1UL<<9)
+
+// USB Control register
+#define RD_EN (1<<0)
+#define WR_EN (1<<1)
+#define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2)
+
+// USB Receive Packet Length register
+#define DV      (1UL<<10)
+#define PKT_RDY (1UL<<11)
+#define PKT_LNGTH_MASK (0x3ff)
+
+// Serial Interface Engine (SIE)
+#define SIE_WRITE   (0x01)
+#define SIE_READ    (0x02)
+#define SIE_COMMAND (0x05)
+#define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))
+
+// SIE Command codes
+#define SIE_CMD_SET_ADDRESS        (0xD0)
+#define SIE_CMD_CONFIGURE_DEVICE   (0xD8)
+#define SIE_CMD_SET_MODE           (0xF3)
+#define SIE_CMD_READ_FRAME_NUMBER  (0xF5)
+#define SIE_CMD_READ_TEST_REGISTER (0xFD)
+#define SIE_CMD_SET_DEVICE_STATUS  (0xFE)
+#define SIE_CMD_GET_DEVICE_STATUS  (0xFE)
+#define SIE_CMD_GET_ERROR_CODE     (0xFF)
+#define SIE_CMD_READ_ERROR_STATUS  (0xFB)
+
+#define SIE_CMD_SELECT_ENDPOINT(endpoint)                 (0x00+endpoint)
+#define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint)
+#define SIE_CMD_SET_ENDPOINT_STATUS(endpoint)             (0x40+endpoint)
+
+#define SIE_CMD_CLEAR_BUFFER    (0xF2)
+#define SIE_CMD_VALIDATE_BUFFER (0xFA)
+
+// SIE Device Status register
+#define SIE_DS_CON    (1<<0)
+#define SIE_DS_CON_CH (1<<1)
+#define SIE_DS_SUS    (1<<2)
+#define SIE_DS_SUS_CH (1<<3)
+#define SIE_DS_RST    (1<<4)
+
+// SIE Device Set Address register
+#define SIE_DSA_DEV_EN  (1<<7)
+
+// SIE Configue Device register
+#define SIE_CONF_DEVICE (1<<0)
+
+// Select Endpoint register
+#define SIE_SE_FE       (1<<0)
+#define SIE_SE_ST       (1<<1)
+#define SIE_SE_STP      (1<<2)
+#define SIE_SE_PO       (1<<3)
+#define SIE_SE_EPN      (1<<4)
+#define SIE_SE_B_1_FULL (1<<5)
+#define SIE_SE_B_2_FULL (1<<6)
+
+// Set Endpoint Status command
+#define SIE_SES_ST      (1<<0)
+#define SIE_SES_DA      (1<<5)
+#define SIE_SES_RF_MO   (1<<6)
+#define SIE_SES_CND_ST  (1<<7)
+
+
+USBHAL * USBHAL::instance;
+
+volatile int epComplete;
+uint32_t endpointStallState;
+
+static void SIECommand(uint32_t command)
+{
+    // The command phase of a SIE transaction
+    LPC_USB->USBDevIntClr = CCEMPTY;
+    LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command);
+    while (!(LPC_USB->USBDevIntSt & CCEMPTY));
+}
+
+static void SIEWriteData(uint8_t data)
+{
+    // The data write phase of a SIE transaction
+    LPC_USB->USBDevIntClr = CCEMPTY;
+    LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data);
+    while (!(LPC_USB->USBDevIntSt & CCEMPTY));
+}
+
+static uint8_t SIEReadData(uint32_t command)
+{
+    // The data read phase of a SIE transaction
+    LPC_USB->USBDevIntClr = CDFULL;
+    LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command);
+    while (!(LPC_USB->USBDevIntSt & CDFULL));
+    return (uint8_t)LPC_USB->USBCmdData;
+}
+
+static void SIEsetDeviceStatus(uint8_t status)
+{
+    // Write SIE device status register
+    SIECommand(SIE_CMD_SET_DEVICE_STATUS);
+    SIEWriteData(status);
+}
+
+static uint8_t SIEgetDeviceStatus(void)
+{
+    // Read SIE device status register
+    SIECommand(SIE_CMD_GET_DEVICE_STATUS);
+    return SIEReadData(SIE_CMD_GET_DEVICE_STATUS);
+}
+
+void SIEsetAddress(uint8_t address)
+{
+    // Write SIE device address register
+    SIECommand(SIE_CMD_SET_ADDRESS);
+    SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN);
+}
+
+static uint8_t SIEselectEndpoint(uint8_t endpoint)
+{
+    // SIE select endpoint command
+    SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint));
+    return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint));
+}
+
+static uint8_t SIEclearBuffer(void)
+{
+    // SIE clear buffer command
+    SIECommand(SIE_CMD_CLEAR_BUFFER);
+    return SIEReadData(SIE_CMD_CLEAR_BUFFER);
+}
+
+static void SIEvalidateBuffer(void)
+{
+    // SIE validate buffer command
+    SIECommand(SIE_CMD_VALIDATE_BUFFER);
+}
+
+static void SIEsetEndpointStatus(uint8_t endpoint, uint8_t status)
+{
+    // SIE set endpoint status command
+    SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint));
+    SIEWriteData(status);
+}
+
+static uint16_t SIEgetFrameNumber(void) __attribute__ ((unused));
+static uint16_t SIEgetFrameNumber(void)
+{
+    // Read current frame number
+    uint16_t lowByte;
+    uint16_t highByte;
+
+    SIECommand(SIE_CMD_READ_FRAME_NUMBER);
+    lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
+    highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
+
+    return (highByte << 8) | lowByte;
+}
+
+static void SIEconfigureDevice(void)
+{
+    // SIE Configure device command
+    SIECommand(SIE_CMD_CONFIGURE_DEVICE);
+    SIEWriteData(SIE_CONF_DEVICE);
+}
+
+static void SIEunconfigureDevice(void)
+{
+    // SIE Configure device command
+    SIECommand(SIE_CMD_CONFIGURE_DEVICE);
+    SIEWriteData(0);
+}
+
+static void SIEconnect(void)
+{
+    // Connect USB device
+    uint8_t status;
+
+    status = SIEgetDeviceStatus();
+    SIEsetDeviceStatus(status | SIE_DS_CON);
+}
+
+
+static void SIEdisconnect(void)
+{
+    // Disconnect USB device
+    uint8_t status;
+
+    status = SIEgetDeviceStatus();
+    SIEsetDeviceStatus(status & ~SIE_DS_CON);
+}
+
+
+static uint8_t selectEndpointClearInterrupt(uint8_t endpoint)
+{
+    // Implemented using using EP_INT_CLR.
+    LPC_USB->USBEpIntClr = EP(endpoint);
+    while (!(LPC_USB->USBDevIntSt & CDFULL));
+    return (uint8_t)LPC_USB->USBCmdData;
+}
+
+
+
+
+
+static void enableEndpointEvent(uint8_t endpoint)
+{
+    // Enable an endpoint interrupt
+    LPC_USB->USBEpIntEn |= EP(endpoint);
+}
+
+static void disableEndpointEvent(uint8_t endpoint) __attribute__ ((unused));
+static void disableEndpointEvent(uint8_t endpoint)
+{
+    // Disable an endpoint interrupt
+    LPC_USB->USBEpIntEn &= ~EP(endpoint);
+}
+
+static volatile uint32_t __attribute__((used)) dummyRead;
+
+
+static uint32_t endpointReadcore(uint8_t endpoint, uint8_t *buffer)
+{
+    // Read from an OUT endpoint
+    uint32_t size;
+    uint32_t i;
+    uint32_t data = 0;
+    uint8_t offset;
+
+    LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;
+    while (!(LPC_USB->USBRxPLen & PKT_RDY));
+
+    size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;
+
+    offset = 0;
+
+    if (size > 0)
+    {
+        for (i=0; i<size; i++)
+        {
+            if (offset==0)
+            {
+                // Fetch up to four bytes of data as a word
+                data = LPC_USB->USBRxData;
+            }
+
+            // extract a byte
+            *buffer = (data>>offset) & 0xff;
+            buffer++;
+
+            // move on to the next byte
+            offset = (offset + 8) % 32;
+        }
+    }
+    else
+    {
+        dummyRead = LPC_USB->USBRxData;
+    }
+
+    SIEselectEndpoint(endpoint);
+    SIEclearBuffer();
+    return size;
+}
+
+static void endpointWritecore(uint8_t endpoint, uint8_t *buffer, uint32_t size)
+{
+    // Write to an IN endpoint
+    uint32_t temp, data;
+    uint8_t offset;
+
+    LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;
+
+    LPC_USB->USBTxPLen = size;
+    offset = 0;
+    data = 0;
+
+    if (size>0)
+    {
+        do {
+            // Fetch next data byte into a word-sized temporary variable
+            temp = *buffer++;
+
+            // Add to current data word
+            temp = temp << offset;
+            data = data | temp;
+
+            // move on to the next byte
+            offset = (offset + 8) % 32;
+            size--;
+
+            if ((offset==0) || (size==0))
+            {
+                // Write the word to the endpoint
+                LPC_USB->USBTxData = data;
+                data = 0;
+            }
+        } while (size>0);
+    }
+    else
+    {
+        LPC_USB->USBTxData = 0;
+    }
+
+    // Clear WR_EN to cover zero length packet case
+    LPC_USB->USBCtrl=0;
+
+    SIEselectEndpoint(endpoint);
+    SIEvalidateBuffer();
+}
+
+
+
+
+
+
+
+USBHAL::USBHAL(void)
+{
+    // Disable IRQ
+    NVIC_DisableIRQ(USB_IRQn);
+
+    // Enable power to USB device controller
+    LPC_SC->PCONP |= PCUSB;
+
+    // Enable USB clocks
+    LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
+    while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
+
+    // Configure pins P0.29 and P0.30 to be USB D+ and USB D-
+    LPC_PINCON->PINSEL1 &= 0xc3ffffff;
+    LPC_PINCON->PINSEL1 |= 0x14000000;
+
+    // Disconnect USB device
+    SIEdisconnect();
+
+    // Configure pin P2.9 to be Connect
+    LPC_PINCON->PINSEL4 &= 0xfffcffff;
+    LPC_PINCON->PINSEL4 |= 0x00040000;
+
+    // Connect must be low for at least 2.5uS
+    wait(0.3);
+
+    // Set the maximum packet size for the control endpoints
+    realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);
+    realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
+
+    // Attach IRQ
+    instance = this;
+    NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
+    NVIC_EnableIRQ(USB_IRQn);
+
+    // Enable interrupts for device events and EP0
+    LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT;
+    enableEndpointEvent(EP0IN);
+    enableEndpointEvent(EP0OUT);
+}
+
+USBHAL::~USBHAL(void)
+{
+    // Ensure device disconnected
+    SIEdisconnect();
+
+    // Disable USB interrupts
+    NVIC_DisableIRQ(USB_IRQn);
+}
+
+void USBHAL::connect(void)
+{
+    // Connect USB device
+    SIEconnect();
+}
+
+void USBHAL::disconnect(void)
+{
+    // Disconnect USB device
+    SIEdisconnect();
+}
+
+void USBHAL::configureDevice(void)
+{
+    SIEconfigureDevice();
+}
+
+void USBHAL::unconfigureDevice(void)
+{
+    SIEunconfigureDevice();
+}
+
+void USBHAL::setAddress(uint8_t address)
+{
+    SIEsetAddress(address);
+}
+
+void USBHAL::EP0setup(uint8_t *buffer)
+{
+    endpointReadcore(EP0OUT, buffer);
+}
+
+void USBHAL::EP0read(void)
+{
+    // Not required
+}
+
+uint32_t USBHAL::EP0getReadResult(uint8_t *buffer)
+{
+    return endpointReadcore(EP0OUT, buffer);
+}
+
+void USBHAL::EP0write(uint8_t *buffer, uint32_t size)
+{
+    endpointWritecore(EP0IN, buffer, size);
+}
+
+void USBHAL::EP0getWriteResult(void)
+{
+    // Not required
+}
+
+void USBHAL::EP0stall(void)
+{
+    // This will stall both control endpoints
+    stallEndpoint(EP0OUT);
+}
+
+EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize)
+{
+    return EP_PENDING;
+}
+
+EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_t *bytesRead)
+{
+    if(!(epComplete & EP(endpoint)))
+        return EP_PENDING;
+    *bytesRead = endpointReadcore(endpoint, buffer);
+    epComplete &= ~EP(endpoint);
+    return EP_COMPLETED;
+}
+
+EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
+{
+    if (getEndpointStallState(endpoint))
+    {
+        return EP_STALLED;
+    }
+
+    epComplete &= ~EP(endpoint);
+
+    endpointWritecore(endpoint, data, size);
+    return EP_PENDING;
+}
+
+EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint)
+{
+    if (epComplete & EP(endpoint))
+    {
+        epComplete &= ~EP(endpoint);
+        return EP_COMPLETED;
+    }
+
+    return EP_PENDING;
+}
+
+bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags)
+{
+    // Realise an endpoint
+    LPC_USB->USBDevIntClr = EP_RLZED;
+    LPC_USB->USBReEp |= EP(endpoint);
+    LPC_USB->USBEpInd = endpoint;
+    LPC_USB->USBMaxPSize = maxPacket;
+
+    while (!(LPC_USB->USBDevIntSt & EP_RLZED));
+    LPC_USB->USBDevIntClr = EP_RLZED;
+
+    // Clear stall state
+    endpointStallState &= ~EP(endpoint);
+
+    enableEndpointEvent(endpoint);
+    return true;
+}
+
+void USBHAL::stallEndpoint(uint8_t endpoint)
+{
+    // Stall an endpoint
+    if ( (endpoint==EP0IN) || (endpoint==EP0OUT) )
+    {
+        // Conditionally stall both control endpoints
+        SIEsetEndpointStatus(EP0OUT, SIE_SES_CND_ST);
+    }
+    else
+    {
+        SIEsetEndpointStatus(endpoint, SIE_SES_ST);
+
+        // Update stall state
+        endpointStallState |= EP(endpoint);
+    }
+}
+
+void USBHAL::unstallEndpoint(uint8_t endpoint)
+{
+    // Unstall an endpoint. The endpoint will also be reinitialised
+    SIEsetEndpointStatus(endpoint, 0);
+
+    // Update stall state
+    endpointStallState &= ~EP(endpoint);
+}
+
+bool USBHAL::getEndpointStallState(uint8_t endpoint)
+{
+    // Returns true if endpoint stalled
+    return endpointStallState & EP(endpoint);
+}
+
+void USBHAL::remoteWakeup(void)
+{
+    // Remote wakeup
+    uint8_t status;
+
+    // Enable USB clocks
+    LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
+    while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
+
+    status = SIEgetDeviceStatus();
+    SIEsetDeviceStatus(status & ~SIE_DS_SUS);
+}
+
+void USBHAL::NakIntEnable(int frameNumber){
+    SIECommand(SIE_CMD_SET_MODE);
+    SIEWriteData(EP(frameNumber));
+}
+
+
+
+
+void USBHAL::_usbisr(void)
+{
+    instance->usbisr();
+} 
+
+
+void USBHAL::usbisr(void)
+{ 
+    uint8_t devStat;
+
+    if (LPC_USB->USBDevIntSt & FRAME)
+    {
+        // Start of frame event
+        SOF(SIEgetFrameNumber());
+        // Clear interrupt status flag
+        LPC_USB->USBDevIntClr = FRAME;
+    }
+
+    if (LPC_USB->USBDevIntSt & DEV_STAT)
+    {
+        // Device Status interrupt
+        // Must clear the interrupt status flag before reading the device status from the SIE
+        LPC_USB->USBDevIntClr = DEV_STAT;
+
+        // Read device status from SIE
+        devStat = SIEgetDeviceStatus();
+
+        if (devStat & SIE_DS_RST)
+        {
+            // Bus reset
+            busReset();
+        }
+    }
+
+    if (LPC_USB->USBDevIntSt & EP_SLOW)
+    {
+        DBG("Slow %x\r\n", LPC_USB->USBEpIntSt);
+        // (Slow) Endpoint Interrupt
+
+        // Process each endpoint interrupt
+        if (LPC_USB->USBEpIntSt & EP(EP0OUT))
+        {
+            if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP)
+            {
+                // this is a setup packet
+                EP0setupCallback();
+            }
+            else
+            {
+                EP0out();
+            }
+            LPC_USB->USBDevIntClr = EP_SLOW;
+        }
+
+        if (LPC_USB->USBEpIntSt & EP(EP0IN))
+        {
+            selectEndpointClearInterrupt(EP0IN);
+            LPC_USB->USBDevIntClr = EP_SLOW;
+            EP0in();
+        }
+
+        // TODO: This should cover all endpoints, not just EP1,2,3:
+        if (LPC_USB->USBEpIntSt & EP(EP1IN))
+        {
+            selectEndpointClearInterrupt(EP1IN);
+            epComplete |= EP(EP1IN);
+            LPC_USB->USBDevIntClr = EP_SLOW;
+        }
+
+        if (LPC_USB->USBEpIntSt & EP(EP1OUT))
+        {
+            selectEndpointClearInterrupt(EP1OUT);
+            epComplete |= EP(EP1OUT);
+            LPC_USB->USBDevIntClr = EP_SLOW;
+        }
+
+        if (LPC_USB->USBEpIntSt & EP(EP2IN))
+        {
+            selectEndpointClearInterrupt(EP2IN);
+            epComplete |= EP(EP2IN);
+            LPC_USB->USBDevIntClr = EP_SLOW;
+            if(EPBULK_IN_callback())
+                epComplete &= ~EP(EPBULK_IN);
+        }
+
+        if (LPC_USB->USBEpIntSt & EP(EP2OUT))
+        {
+            selectEndpointClearInterrupt(EP2OUT);
+            epComplete |= EP(EP2OUT);
+            LPC_USB->USBDevIntClr = EP_SLOW;
+            if(EPBULK_OUT_callback())
+                epComplete &= ~EP(EPBULK_OUT);
+        }
+
+        if (LPC_USB->USBEpIntSt & EP(EP3IN))
+        {
+            selectEndpointClearInterrupt(EP3IN);
+            epComplete |= EP(EP3IN);
+            LPC_USB->USBDevIntClr = EP_SLOW;
+        }
+
+        if (LPC_USB->USBEpIntSt & EP(EP3OUT))
+        {
+            selectEndpointClearInterrupt(EP3OUT);
+            epComplete |= EP(EP3OUT);
+            LPC_USB->USBDevIntClr = EP_SLOW;
+        }
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBDescriptor.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,60 @@
+/* USBDescriptor.h */
+/* Definitions and macros for constructing USB descriptors */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+/* Standard descriptor types */
+#define DEVICE_DESCRIPTOR        (1)
+#define CONFIGURATION_DESCRIPTOR (2)
+#define STRING_DESCRIPTOR        (3)
+#define INTERFACE_DESCRIPTOR     (4)
+#define ENDPOINT_DESCRIPTOR      (5)
+#define QUALIFIER_DESCRIPTOR     (6)
+
+/* Standard descriptor lengths */
+#define DEVICE_DESCRIPTOR_LENGTH        (0x12)
+#define CONFIGURATION_DESCRIPTOR_LENGTH (0x09)
+#define INTERFACE_DESCRIPTOR_LENGTH     (0x09)
+#define ENDPOINT_DESCRIPTOR_LENGTH      (0x07)
+
+
+/*string offset*/
+#define STRING_OFFSET_LANGID            (0) 
+#define STRING_OFFSET_IMANUFACTURER     (1)
+#define STRING_OFFSET_IPRODUCT          (2)
+#define STRING_OFFSET_ISERIAL           (3)
+#define STRING_OFFSET_ICONFIGURATION    (4)
+#define STRING_OFFSET_IINTERFACE        (5)
+
+/* USB Specification Release Number */
+#define USB_VERSION_2_0 (0x0200)
+
+/* Least/Most significant byte of short integer */
+#define LSB(n)  ((n)&0xff)
+#define MSB(n)  (((n)&0xff00)>>8)
+
+/* Convert physical endpoint number to descriptor endpoint number */
+#define PHY_TO_DESC(endpoint) (((endpoint)>>1) | (((endpoint) & 1) ? 0x80:0))
+
+/* bmAttributes in configuration descriptor */
+/* C_RESERVED must always be set */
+#define C_RESERVED      (1U<<7)
+#define C_SELF_POWERED  (1U<<6)
+#define C_REMOTE_WAKEUP (1U<<5)
+
+/* bMaxPower in configuration descriptor */
+#define C_POWER(mA)     ((mA)/2)
+
+/* bmAttributes in endpoint descriptor */
+#define E_CONTROL       (0x00)
+#define E_ISOCHRONOUS   (0x01)
+#define E_BULK          (0x02)
+#define E_INTERRUPT     (0x03)
+
+/* For isochronous endpoints only: */
+#define E_NO_SYNCHRONIZATION    (0x00)
+#define E_ASYNCHRONOUS          (0x04)
+#define E_ADAPTIVE              (0x08)
+#define E_SYNCHRONOUS           (0x0C)
+#define E_DATA                  (0x00)
+#define E_FEEDBACK              (0x10)
+#define E_IMPLICIT_FEEDBACK     (0x20)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBDevice.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,915 @@
+/* USBDevice.c */
+/* Generic USB device */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+/* Reference: */
+/* Universal Serial Bus Specification Revision 2.0, Chapter 9 "USB Device Framework" */
+
+//#define DEBUG
+#include "dbg.h"
+#include "stdint.h"
+
+#include "USBEndpoints.h"
+#include "USBDevice.h"
+#include "USBDescriptor.h"
+#include "USBHID_Types.h"
+
+
+/* Device status */
+#define DEVICE_STATUS_SELF_POWERED  (1U<<0)
+#define DEVICE_STATUS_REMOTE_WAKEUP (1U<<1)
+
+/* Endpoint status */
+#define ENDPOINT_STATUS_HALT        (1U<<0)
+
+/* Standard feature selectors */
+#define DEVICE_REMOTE_WAKEUP        (1)
+#define ENDPOINT_HALT               (0)
+
+/* Macro to convert wIndex endpoint number to physical endpoint number */
+#define WINDEX_TO_PHYSICAL(endpoint) (((endpoint & 0x0f) << 1) + \
+    ((endpoint & 0x80) ? 1 : 0))
+
+
+bool USBDevice::requestGetDescriptor(void)
+{
+    bool success = false;
+
+    switch (DESCRIPTOR_TYPE(transfer.setup.wValue))
+    {
+        case DEVICE_DESCRIPTOR:
+        case QUALIFIER_DESCRIPTOR:
+            if (deviceDesc() != NULL)
+            {
+                if ((deviceDesc()[0] == DEVICE_DESCRIPTOR_LENGTH) \
+                    && (deviceDesc()[1] == DEVICE_DESCRIPTOR))
+                {
+                    transfer.remaining = DEVICE_DESCRIPTOR_LENGTH;
+                    transfer.ptr = deviceDesc();
+                    transfer.direction = DEVICE_TO_HOST;
+                    success = true;
+                }
+            }
+            break;
+        case CONFIGURATION_DESCRIPTOR:
+            if (configurationDesc() != NULL)
+            {
+                if ((configurationDesc()[0] == CONFIGURATION_DESCRIPTOR_LENGTH) \
+                    && (configurationDesc()[1] == CONFIGURATION_DESCRIPTOR))
+                {
+                    /* Get wTotalLength */
+                    transfer.remaining = configurationDesc()[2] \
+                        | (configurationDesc()[3] << 8);
+
+                    transfer.ptr = configurationDesc();
+                    transfer.direction = DEVICE_TO_HOST;
+                    success = true;
+                }
+            }
+            break;
+        case STRING_DESCRIPTOR:
+            switch (DESCRIPTOR_INDEX(transfer.setup.wValue))
+            {
+                            case STRING_OFFSET_LANGID:
+                                transfer.remaining = stringLangidDesc()[0];
+                                transfer.ptr = stringLangidDesc();
+                                transfer.direction = DEVICE_TO_HOST;
+                                success = true;
+                                break;
+                            case STRING_OFFSET_IMANUFACTURER:
+                                transfer.remaining =  stringImanufacturerDesc()[0];
+                                transfer.ptr = stringImanufacturerDesc();
+                                transfer.direction = DEVICE_TO_HOST;
+                                success = true;
+                                break;       
+                            case STRING_OFFSET_IPRODUCT:
+                                transfer.remaining = stringIproductDesc()[0];
+                                transfer.ptr = stringIproductDesc();
+                                transfer.direction = DEVICE_TO_HOST;
+                                success = true;
+                                break;            
+                            case STRING_OFFSET_ISERIAL:
+                                transfer.remaining = stringIserialDesc()[0];
+                                transfer.ptr = stringIserialDesc();
+                                transfer.direction = DEVICE_TO_HOST;
+                                success = true;
+                                break;        
+                            case STRING_OFFSET_ICONFIGURATION:
+                                transfer.remaining = stringIConfigurationDesc()[0];
+                                transfer.ptr = stringIConfigurationDesc();
+                                transfer.direction = DEVICE_TO_HOST;
+                                success = true;
+                                break; 
+                            case STRING_OFFSET_IINTERFACE:
+                                transfer.remaining = stringIinterfaceDesc()[0];
+                                transfer.ptr = stringIinterfaceDesc();
+                                transfer.direction = DEVICE_TO_HOST;
+                                success = true;
+                                break; 
+            }
+            break;
+        case INTERFACE_DESCRIPTOR:
+        case ENDPOINT_DESCRIPTOR:
+            /* TODO: Support is optional, not implemented here */
+            break;
+        default:
+            break;
+    }
+
+    return success;
+}
+
+void USBDevice::decodeSetupPacket(uint8_t *data, SETUP_PACKET *packet)
+{
+    /* Fill in the elements of a SETUP_PACKET structure from raw data */
+    packet->bmRequestType.dataTransferDirection = (data[0] & 0x80) >> 7;
+    packet->bmRequestType.Type = (data[0] & 0x60) >> 5;
+    packet->bmRequestType.Recipient = data[0] & 0x1f;
+    packet->bRequest = data[1];
+    packet->wValue = (data[2] | (uint16_t)data[3] << 8);
+    packet->wIndex = (data[4] | (uint16_t)data[5] << 8);
+    packet->wLength = (data[6] | (uint16_t)data[7] << 8);
+}
+
+
+bool USBDevice::controlOut(void)
+{
+    /* Control transfer data OUT stage */
+    uint8_t buffer[MAX_PACKET_SIZE_EP0];
+    uint32_t packetSize;
+
+    /* Check we should be transferring data OUT */
+    if (transfer.direction != HOST_TO_DEVICE)
+    {
+        return false;
+    }
+
+    /* Read from endpoint */
+    packetSize = EP0getReadResult(buffer);
+
+    /* Check if transfer size is valid */
+    if (packetSize > transfer.remaining)
+    {
+        /* Too big */
+        return false;
+    }
+
+    /* Update transfer */
+    transfer.ptr += packetSize;
+    transfer.remaining -= packetSize;
+
+    /* Check if transfer has completed */
+    if (transfer.remaining == 0)
+    {
+        /* Transfer completed */
+        if (transfer.notify)
+        {
+            /* Notify class layer. */
+            USBCallback_requestCompleted();
+            transfer.notify = false;
+        }
+        /* Status stage */
+        EP0write(NULL, 0);
+    }
+    else
+    {
+        EP0read();
+    }
+
+    return true;
+}
+
+bool USBDevice::controlIn(void)
+{
+    /* Control transfer data IN stage */
+    uint32_t packetSize;
+
+    /* Check if transfer has completed (status stage transactions */
+    /* also have transfer.remaining == 0) */
+    if (transfer.remaining == 0)
+    {
+        if (transfer.zlp)
+        {
+            /* Send zero length packet */
+            EP0write(NULL, 0);
+            transfer.zlp = false;
+        }
+
+        /* Transfer completed */
+        if (transfer.notify)
+        {
+            /* Notify class layer. */
+            USBCallback_requestCompleted();
+            transfer.notify = false;
+        }
+
+        EP0read();
+
+        /* Completed */
+        return true;
+    }
+
+    /* Check we should be transferring data IN */
+    if (transfer.direction != DEVICE_TO_HOST)
+    {
+        return false;
+    }
+
+    packetSize = transfer.remaining;
+
+    if (packetSize > MAX_PACKET_SIZE_EP0)
+    {
+        packetSize = MAX_PACKET_SIZE_EP0;
+    }
+
+    /* Write to endpoint */
+    EP0write(transfer.ptr, packetSize);
+
+    /* Update transfer */
+    transfer.ptr += packetSize;
+    transfer.remaining -= packetSize;
+
+    return true;
+}
+
+bool USBDevice::requestSetAddress(void)
+{
+    /* Set the device address */
+    setAddress(transfer.setup.wValue);
+
+    if (transfer.setup.wValue == 0)
+    {
+        device.state = DEFAULT;
+    }
+    else
+    {
+        device.state = ADDRESS;
+    }
+
+    return true;
+}
+
+bool USBDevice::requestSetConfiguration(void)
+{
+
+    device.configuration = transfer.setup.wValue;
+    /* Set the device configuration */
+    if (device.configuration == 0)
+    {
+        /* Not configured */
+        unconfigureDevice();
+        device.state = ADDRESS;
+    }
+    else
+    {
+        if (USBCallback_setConfiguration(device.configuration))
+        {
+            /* Valid configuration */
+            configureDevice();
+            device.state = CONFIGURED;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool USBDevice::requestGetConfiguration(void)
+{
+    /* Send the device configuration */
+    transfer.ptr = &device.configuration;
+    transfer.remaining = sizeof(device.configuration);
+    transfer.direction = DEVICE_TO_HOST;
+    return true;
+}
+
+bool USBDevice::requestGetInterface(void)
+{
+    static uint8_t alternateSetting;
+
+    /* Return the selected alternate setting for an interface */
+
+    if (device.state != CONFIGURED)
+    {
+        return false;
+    }
+
+    /* TODO: We currently do not support alternate settings */
+    /* so always return zero */
+    /* TODO: Should check that the interface number is valid */
+    alternateSetting = 0;
+
+    /* Send the alternate setting */
+    transfer.ptr = &alternateSetting;
+    transfer.remaining = sizeof(alternateSetting);
+    transfer.direction = DEVICE_TO_HOST;
+    return true;
+}
+
+bool USBDevice::requestSetInterface(void)
+{
+    /* TODO: We currently do not support alternate settings, return false */
+    return false;
+}
+
+bool USBDevice::requestSetFeature()
+{
+    bool success = false;
+
+    if (device.state != CONFIGURED)
+    {
+        /* Endpoint or interface must be zero */
+        if (transfer.setup.wIndex != 0)
+        {
+            return false;
+        }
+    }
+
+    switch (transfer.setup.bmRequestType.Recipient)
+    {
+        case DEVICE_RECIPIENT:
+            /* TODO: Remote wakeup feature not supported */
+            break;
+        case ENDPOINT_RECIPIENT:
+            if (transfer.setup.wValue == ENDPOINT_HALT)
+            {
+                /* TODO: We should check that the endpoint number is valid */
+                stallEndpoint(
+                    WINDEX_TO_PHYSICAL(transfer.setup.wIndex));
+                success = true;
+            }
+            break;
+        default:
+            break;
+    }
+
+    return success;
+}
+
+bool USBDevice::requestClearFeature()
+{
+    bool success = false;
+
+    if (device.state != CONFIGURED)
+    {
+        /* Endpoint or interface must be zero */
+        if (transfer.setup.wIndex != 0)
+        {
+            return false;
+        }
+    }
+
+    switch (transfer.setup.bmRequestType.Recipient)
+    {
+        case DEVICE_RECIPIENT:
+            /* TODO: Remote wakeup feature not supported */
+            break;
+        case ENDPOINT_RECIPIENT:
+            /* TODO: We should check that the endpoint number is valid */
+            if (transfer.setup.wValue == ENDPOINT_HALT)
+            {
+                unstallEndpoint(
+                    WINDEX_TO_PHYSICAL(transfer.setup.wIndex));
+                success = true;
+            }
+            break;
+        default:
+            break;
+    }
+
+    return success;
+}
+
+bool USBDevice::requestGetStatus(void)
+{
+    static uint16_t status;
+    bool success = false;
+
+    if (device.state != CONFIGURED)
+    {
+        /* Endpoint or interface must be zero */
+        if (transfer.setup.wIndex != 0)
+        {
+            return false;
+        }
+    }
+
+    switch (transfer.setup.bmRequestType.Recipient)
+    {
+        case DEVICE_RECIPIENT:
+            /* TODO: Currently only supports self powered devices */
+            status = DEVICE_STATUS_SELF_POWERED;
+            success = true;
+            break;
+        case INTERFACE_RECIPIENT:
+            status = 0;
+            success = true;
+            break;
+        case ENDPOINT_RECIPIENT:
+            /* TODO: We should check that the endpoint number is valid */
+            if (getEndpointStallState(
+                WINDEX_TO_PHYSICAL(transfer.setup.wIndex)))
+            {
+                status = ENDPOINT_STATUS_HALT;
+            }
+            else
+            {
+                status = 0;
+            }
+            success = true;
+            break;
+        default:
+            break;
+    }
+
+    if (success)
+    {
+        /* Send the status */ 
+        transfer.ptr = (uint8_t *)&status; /* Assumes little endian */
+        transfer.remaining = sizeof(status);
+        transfer.direction = DEVICE_TO_HOST;
+    }
+    
+    return success;
+}
+
+bool USBDevice::requestSetup(void)
+{
+    bool success = false;
+
+    /* Process standard requests */
+    if ((transfer.setup.bmRequestType.Type == STANDARD_TYPE))
+    {
+        switch (transfer.setup.bRequest)
+        {
+             case GET_STATUS:
+                 success = requestGetStatus();
+                 break;
+             case CLEAR_FEATURE:
+                 success = requestClearFeature();
+                 break;
+             case SET_FEATURE:
+                 success = requestSetFeature();
+                 break;
+             case SET_ADDRESS:
+                success = requestSetAddress();
+                 break;
+             case GET_DESCRIPTOR:
+                 success = requestGetDescriptor();
+                 break;
+             case SET_DESCRIPTOR:
+                 /* TODO: Support is optional, not implemented here */
+                 success = false;
+                 break;
+             case GET_CONFIGURATION:
+                 success = requestGetConfiguration();
+                 break;
+             case SET_CONFIGURATION:
+                 success = requestSetConfiguration();
+                 break;
+             case GET_INTERFACE:
+                 success = requestGetInterface();
+                 break;
+             case SET_INTERFACE:
+                 success = requestSetInterface();
+                 break;
+             default:
+                 break;
+        }
+    }
+
+    return success;
+}
+
+bool USBDevice::controlSetup(void)
+{
+    bool success = false;
+
+    /* Control transfer setup stage */
+    uint8_t buffer[MAX_PACKET_SIZE_EP0];
+
+    EP0setup(buffer);
+
+    /* Initialise control transfer state */
+    decodeSetupPacket(buffer, &transfer.setup);
+    transfer.ptr = NULL;
+    transfer.remaining = 0;
+    transfer.direction = 0;
+    transfer.zlp = false;
+    transfer.notify = false;
+
+    /* Process request */
+
+    /* Class / vendor specific */
+    success = USBCallback_request();
+
+    if (!success)
+    {
+        /* Standard requests */
+        if (!requestSetup())
+        {
+            return false;
+        }
+    }
+
+    /* Check transfer size and direction */
+    if (transfer.setup.wLength>0)
+    {
+        if (transfer.setup.bmRequestType.dataTransferDirection \
+            == DEVICE_TO_HOST)
+        {
+            /* IN data stage is required */
+            if (transfer.direction != DEVICE_TO_HOST)
+            {
+                return false;
+            }
+
+            /* Transfer must be less than or equal to the size */
+            /* requested by the host */
+            if (transfer.remaining > transfer.setup.wLength)
+            {
+                transfer.remaining = transfer.setup.wLength;
+            }
+        }
+        else
+        {
+            
+            /* OUT data stage is required */
+            if (transfer.direction != HOST_TO_DEVICE)
+            {
+                return false;
+            }
+
+            /* Transfer must be equal to the size requested by the host */
+            if (transfer.remaining != transfer.setup.wLength)
+            {
+                return false;
+            }
+        }
+    }
+    else
+    {
+        /* No data stage; transfer size must be zero */
+        if (transfer.remaining != 0)
+        {
+            return false;
+        }
+    }
+
+    /* Data or status stage if applicable */
+    if (transfer.setup.wLength>0)
+    {
+        if (transfer.setup.bmRequestType.dataTransferDirection \
+            == DEVICE_TO_HOST)
+        {
+            /* Check if we'll need to send a zero length packet at */
+            /* the end of this transfer */
+            if (transfer.setup.wLength > transfer.remaining)
+            {
+                /* Device wishes to transfer less than host requested */
+                if ((transfer.remaining % MAX_PACKET_SIZE_EP0) == 0)
+                {
+                    /* Transfer is a multiple of EP0 max packet size */
+                    transfer.zlp = true;
+                }
+            }
+
+            /* IN stage */
+            controlIn();
+        }
+        else
+        {
+            /* OUT stage */
+            EP0read();
+        }
+    }
+    else
+    {
+        /* Status stage */
+        EP0write(NULL, 0);
+    }
+
+    return true;
+}
+
+void USBDevice::busReset(void)
+{
+    device.state = DEFAULT;
+    device.configuration = 0;
+    device.suspended = false;
+
+    /* Call class / vendor specific busReset function */
+    USBCallback_busReset();
+}
+
+void USBDevice::EP0setupCallback(void)
+{
+    /* Endpoint 0 setup event */
+    if (!controlSetup())
+    {
+        /* Protocol stall */
+        EP0stall();
+    }
+
+    /* Return true if an OUT data stage is expected */
+}
+
+void USBDevice::EP0out(void)
+{
+    /* Endpoint 0 OUT data event */
+    if (!controlOut())
+    {
+        /* Protocol stall; this will stall both endpoints */
+        EP0stall();
+    }
+}
+
+void USBDevice::EP0in(void)
+{
+    /* Endpoint 0 IN data event */
+    if (!controlIn())
+    {
+        /* Protocol stall; this will stall both endpoints */
+        EP0stall();
+    }
+}
+
+bool USBDevice::configured(void)
+{
+    /* Returns true if device is in the CONFIGURED state */
+    return (device.state == CONFIGURED);
+}
+
+void USBDevice::connect(void)
+{
+    /* Connect device */
+    USBHAL::connect();
+}
+
+void USBDevice::disconnect(void)
+{
+    /* Disconnect device */
+    USBHAL::disconnect();
+}
+
+CONTROL_TRANSFER * USBDevice::getTransferPtr(void)
+{
+    return &transfer;
+}
+
+bool USBDevice::addEndpoint(uint8_t endpoint, uint32_t maxPacket)
+{
+    return realiseEndpoint(endpoint, maxPacket, 0);
+}
+
+bool USBDevice::addRateFeedbackEndpoint(uint8_t endpoint, uint32_t maxPacket)
+{
+    /* For interrupt endpoints only */
+    return realiseEndpoint(endpoint, maxPacket, RATE_FEEDBACK_MODE);
+}
+
+uint8_t * USBDevice::findDescriptor(uint8_t descriptorType)
+{
+    /* Find a descriptor within the list of descriptors */
+    /* following a configuration descriptor. */
+    uint16_t wTotalLength;
+    uint8_t *ptr;
+
+    if (configurationDesc() == NULL)
+    {
+        return NULL;
+    }
+
+    /* Check this is a configuration descriptor */
+    if ((configurationDesc()[0] != CONFIGURATION_DESCRIPTOR_LENGTH) \
+            || (configurationDesc()[1] != CONFIGURATION_DESCRIPTOR))
+    {
+        return NULL;
+    }
+
+    wTotalLength = configurationDesc()[2] | (configurationDesc()[3] << 8);
+
+    /* Check there are some more descriptors to follow */
+    if (wTotalLength <= (CONFIGURATION_DESCRIPTOR_LENGTH+2))
+    /* +2 is for bLength and bDescriptorType of next descriptor */
+    {
+        return false;
+    }
+
+    /* Start at first descriptor after the configuration descriptor */
+    ptr = &(configurationDesc()[CONFIGURATION_DESCRIPTOR_LENGTH]);
+
+    do {
+        if (ptr[1] /* bDescriptorType */ == descriptorType)
+        {
+            /* Found */
+            return ptr;
+        }
+
+        /* Skip to next descriptor */
+        ptr += ptr[0]; /* bLength */
+    } while (ptr < (configurationDesc() + wTotalLength));
+
+    /* Reached end of the descriptors - not found */
+    return NULL;
+}
+
+void USBDevice::SOF(int frameNumber)
+{
+}
+
+void USBDevice::connectStateChanged(unsigned int connected)
+{
+}
+
+void USBDevice::suspendStateChanged(unsigned int suspended)
+{
+}
+
+
+USBDevice::USBDevice(uint16_t vendor_id, uint16_t product_id, uint16_t product_release){
+    VENDOR_ID = vendor_id; 
+    PRODUCT_ID = product_id; 
+    PRODUCT_RELEASE = product_release;
+
+    /* Set initial device state */
+    device.state = POWERED;
+    device.configuration = 0;
+    device.suspended = false;
+
+    connect();
+};
+
+
+bool USBDevice::readStart(uint8_t endpoint, uint16_t maxSize)
+{
+    return endpointRead(endpoint, maxSize) == EP_PENDING;
+}
+
+
+bool USBDevice::write(uint8_t endpoint, uint8_t * buffer, uint16_t size, uint16_t maxSize)
+{
+    EP_STATUS result;
+
+    if (size > maxSize)
+    {
+        return false;
+    }
+
+    /* Block if not configured */
+    while (!configured());
+    
+    /* Send report */
+    result = endpointWrite(endpoint, buffer, size);
+
+    if (result != EP_PENDING)
+    {
+        return false;
+    }
+
+    /* Wait for completion */
+    do {
+        result = endpointWriteResult(endpoint);
+    } while ((result == EP_PENDING) && configured());
+
+    return (result == EP_COMPLETED);
+}
+
+
+bool USBDevice::writeNB(uint8_t endpoint, uint8_t * buffer, uint16_t size, uint16_t maxSize)
+{
+    EP_STATUS result;
+
+    if (size > maxSize)
+    {
+        return false;
+    }
+
+    /* Block if not configured */
+    while (!configured());
+
+    /* Send report */
+    result = endpointWrite(endpoint, buffer, size);
+
+    if (result != EP_PENDING)
+    {
+        return false;
+    }
+
+    result = endpointWriteResult(endpoint);
+
+    return (result == EP_COMPLETED);
+}
+
+
+
+bool USBDevice::read(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize)
+{
+    EP_STATUS result;
+
+    /* Block if not configured */
+    while (!configured());
+
+    /* Wait for completion */
+    do {
+        result = endpointReadResult(endpoint, buffer, (uint32_t *)size);
+    } while ((result == EP_PENDING) && configured());
+
+    return (result == EP_COMPLETED);
+}
+
+
+bool USBDevice::readNB(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize)
+{
+    EP_STATUS result;
+
+    /* Block if not configured */
+    while (!configured());
+
+    result = endpointReadResult(endpoint, buffer, (uint32_t *)size);
+    
+    return (result == EP_COMPLETED);
+}
+
+
+
+uint8_t * USBDevice::deviceDesc() {
+    static uint8_t deviceDescriptor[] = {
+        DEVICE_DESCRIPTOR_LENGTH,       /* bLength */
+        DEVICE_DESCRIPTOR,              /* bDescriptorType */
+        LSB(USB_VERSION_2_0),           /* bcdUSB (LSB) */
+        MSB(USB_VERSION_2_0),           /* bcdUSB (MSB) */
+        0x00,                           /* bDeviceClass */
+        0x00,                           /* bDeviceSubClass */
+        0x00,                           /* bDeviceprotocol */
+        MAX_PACKET_SIZE_EP0,            /* bMaxPacketSize0 */
+        LSB(VENDOR_ID),                 /* idVendor (LSB) */
+        MSB(VENDOR_ID),                 /* idVendor (MSB) */
+        LSB(PRODUCT_ID),                /* idProduct (LSB) */
+        MSB(PRODUCT_ID),                /* idProduct (MSB) */
+        LSB(PRODUCT_RELEASE),           /* bcdDevice (LSB) */
+        MSB(PRODUCT_RELEASE),           /* bcdDevice (MSB) */
+        STRING_OFFSET_IMANUFACTURER,    /* iManufacturer */
+        STRING_OFFSET_IPRODUCT,         /* iProduct */
+        STRING_OFFSET_ISERIAL,          /* iSerialNumber */
+        0x01                            /* bNumConfigurations */
+    };
+    return deviceDescriptor;
+}
+
+uint8_t * USBDevice::stringLangidDesc() {
+    static uint8_t stringLangidDescriptor[] = {
+        0x04,               /*bLength*/
+        STRING_DESCRIPTOR,  /*bDescriptorType 0x03*/
+        0x09,0x00,          /*bString Lang ID - 0x009 - English*/
+    };
+    return stringLangidDescriptor;
+}
+
+uint8_t * USBDevice::stringImanufacturerDesc() {
+    static uint8_t stringImanufacturerDescriptor[] = {
+        0x12,                                            /*bLength*/
+        STRING_DESCRIPTOR,                               /*bDescriptorType 0x03*/
+        'm',0,'b',0,'e',0,'d',0,'.',0,'o',0,'r',0,'g',0, /*bString iManufacturer - mbed.org*/
+    };
+    return stringImanufacturerDescriptor;
+}
+
+uint8_t * USBDevice::stringIserialDesc() {
+    static uint8_t stringIserialDescriptor[] = {
+        0x16,                                                           /*bLength*/
+        STRING_DESCRIPTOR,                                              /*bDescriptorType 0x03*/
+        '0',0,'1',0,'2',0,'3',0,'4',0,'5',0,'6',0,'7',0,'8',0,'9',0,    /*bString iSerial - 0123456789*/
+    };
+    return stringIserialDescriptor;
+}
+
+uint8_t * USBDevice::stringIConfigurationDesc() {
+    static uint8_t stringIconfigurationDescriptor[] = {
+        0x06,               /*bLength*/
+        STRING_DESCRIPTOR,  /*bDescriptorType 0x03*/
+        '0',0,'1',0,        /*bString iConfiguration - 01*/
+    };
+    return stringIconfigurationDescriptor;
+}
+
+uint8_t * USBDevice::stringIinterfaceDesc() {
+    static uint8_t stringIinterfaceDescriptor[] = {
+        0x08,               /*bLength*/
+        STRING_DESCRIPTOR,  /*bDescriptorType 0x03*/
+        'U',0,'S',0,'B',0,  /*bString iInterface - USB*/
+    };
+    return stringIinterfaceDescriptor;
+}
+
+uint8_t * USBDevice::stringIproductDesc() {
+    static uint8_t stringIproductDescriptor[] = {
+        0x16,                                                       /*bLength*/
+        STRING_DESCRIPTOR,                                          /*bDescriptorType 0x03*/
+        'U',0,'S',0,'B',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 /*bString iProduct - USB DEVICE*/
+    };
+    return stringIproductDescriptor;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBDevice.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,231 @@
+/* USBDevice.h */
+/* Generic USB device */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USBDEVICE_H
+#define USBDEVICE_H
+
+#include "mbed.h"
+#include "USBDevice_Types.h"
+#include "USBBusInterface.h"
+
+
+
+class USBDevice: public USBHAL
+{
+public:
+    USBDevice(uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
+    
+    /*
+    * Check if the device is configured
+    *
+    * @returns true if configured, false otherwise
+    */
+    bool configured(void);
+    
+    /*
+    * Connect a device
+    */
+    void connect(void);
+    
+    /*
+    * Disconnect a device
+    */
+    void disconnect(void);
+    
+    /*
+    * Add an endpoint
+    *
+    * @param endpoint endpoint which will be added
+    * @param maxPacket Maximum size of a packet which can be sent for this endpoint
+    * @returns true if successful, false otherwise
+    */
+    bool addEndpoint(uint8_t endpoint, uint32_t maxPacket);
+
+    /*
+    * Start a reading on a certain endpoint.
+    * You can access the result of the reading by USBDevice_read
+    *
+    * @param endpoint endpoint which will be read
+    * @param maxSize the maximum length that can be read
+    * @return true if successful
+    */
+    bool readStart(uint8_t endpoint, uint16_t maxSize);
+    
+    /*
+    * Read a certain endpoint. Before calling this function, USBUSBDevice_readStart
+    * must be called.
+    *
+    * Warning: blocking
+    *
+    * @param endpoint endpoint which will be read
+    * @param buffer buffer will be filled with the data received
+    * @param size the number of bytes read will be stored in *size
+    * @param maxSize the maximum length that can be read
+    * @returns true if successful
+    */
+    bool read(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize);
+    
+    /*
+    * Read a certain endpoint.
+    *
+    * Warning: non blocking
+    *
+    * @param endpoint endpoint which will be read
+    * @param buffer buffer will be filled with the data received (if data are available) 
+    * @param size the number of bytes read will be stored in *size
+    * @param maxSize the maximum length that can be read
+    * @returns true if successful
+    */
+    bool readNB(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize);
+    
+    /*
+    * Write a certain endpoint.
+    *
+    * Warning: blocking
+    *
+    * @param endpoint endpoint to write
+    * @param buffer data contained in buffer will be write
+    * @param size the number of bytes to write
+    * @param maxSize the maximum length that can be written on this endpoint
+    */
+    bool write(uint8_t endpoint, uint8_t * buffer, uint16_t size, uint16_t maxSize);
+    bool writeNB(uint8_t endpoint, uint8_t * buffer, uint16_t size, uint16_t maxSize);
+
+    
+    /*
+    * Called by USBDevice layer on bus reset. Warning: Called in ISR context
+    *
+    * May be used to reset state
+    */
+    virtual void USBCallback_busReset(void) {};
+    
+    /*
+    * Called by USBDevice on Endpoint0 request. Warning: Called in ISR context
+    * This is used to handle extensions to standard requests
+    * and class specific requests
+    *
+    * @returns true if class handles this request
+    */
+    virtual bool USBCallback_request() { return false; };   
+    
+    /*
+    * Called by USBDevice on Endpoint0 request completion
+    * if the 'notify' flag has been set to true. Warning: Called in ISR context
+    *
+    * In this case it is used to indicate that a HID report has
+    * been received from the host on endpoint 0
+    */
+    virtual void USBCallback_requestCompleted() {};
+    
+    /*
+    * Called by USBDevice layer. Set configuration of the device.
+    * For instance, you can add all endpoints that you need on this function.
+    *
+    * @param configuration Number of the configuration
+    */
+    virtual bool USBCallback_setConfiguration(uint8_t configuration) { return false; };
+
+    /*
+    * Get device descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
+    *
+    * @returns pointer to the device descriptor
+    */
+    virtual uint8_t * deviceDesc();
+    
+    /*
+    * Get configuration descriptor
+    *
+    * @returns pointer to the configuration descriptor
+    */
+    virtual uint8_t * configurationDesc(){return NULL;};
+    
+    /*
+    * Get string lang id descriptor
+    *
+    * @return pointer to the string lang id descriptor
+    */
+    virtual uint8_t * stringLangidDesc();
+    
+    /*
+    * Get string manufacturer descriptor
+    *
+    * @returns pointer to the string manufacturer descriptor
+    */
+    virtual uint8_t * stringImanufacturerDesc();
+    
+    /*
+    * Get string product descriptor
+    *
+    * @returns pointer to the string product descriptor
+    */
+    virtual uint8_t * stringIproductDesc();
+    
+    /*
+    * Get string serial descriptor
+    *
+    * @returns pointer to the string serial descriptor
+    */
+    virtual uint8_t * stringIserialDesc();
+    
+    /*
+    * Get string configuration descriptor
+    *
+    * @returns pointer to the string configuration descriptor
+    */
+    virtual uint8_t * stringIConfigurationDesc();
+    
+    /*
+    * Get string interface descriptor
+    *
+    * @returns pointer to the string interface descriptor
+    */
+    virtual uint8_t * stringIinterfaceDesc();
+    
+    /*
+    * Get the length of the report descriptor
+    *
+    * @returns length of the report descriptor
+    */
+    virtual uint16_t reportDescLength() { return 0; };
+    
+
+
+protected:
+    virtual void busReset(void);
+    virtual void EP0setupCallback(void);
+    virtual void EP0out(void);
+    virtual void EP0in(void);
+    virtual void SOF(int frameNumber);
+    virtual void connectStateChanged(unsigned int connected);
+    virtual void suspendStateChanged(unsigned int suspended);
+    uint8_t * findDescriptor(uint8_t descriptorType);
+    CONTROL_TRANSFER * getTransferPtr(void);
+    
+    uint16_t VENDOR_ID;
+    uint16_t PRODUCT_ID;
+    uint16_t PRODUCT_RELEASE;
+
+private:
+    bool addRateFeedbackEndpoint(uint8_t endpoint, uint32_t maxPacket);
+    bool requestGetDescriptor(void);
+    bool controlOut(void);
+    bool controlIn(void);
+    bool requestSetAddress(void);
+    bool requestSetConfiguration(void);
+    bool requestSetFeature(void);
+    bool requestClearFeature(void);
+    bool requestGetStatus(void);
+    bool requestSetup(void);
+    bool controlSetup(void);
+    void decodeSetupPacket(uint8_t *data, SETUP_PACKET *packet);
+    bool requestGetConfiguration(void);
+    bool requestGetInterface(void);
+    bool requestSetInterface(void);
+
+    CONTROL_TRANSFER transfer;
+    USB_DEVICE device;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBDevice_Types.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,69 @@
+/* USBDevice_Types.h */
+/* USB Device type definitions, conversions and constants */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USBDEVICE_TYPES_H
+#define USBDEVICE_TYPES_H
+
+/* Standard requests */
+#define GET_STATUS        (0)
+#define CLEAR_FEATURE     (1)
+#define SET_FEATURE       (3)
+#define SET_ADDRESS       (5)
+#define GET_DESCRIPTOR    (6)
+#define SET_DESCRIPTOR    (7)
+#define GET_CONFIGURATION (8)
+#define SET_CONFIGURATION (9)
+#define GET_INTERFACE     (10)
+#define SET_INTERFACE     (11)
+
+/* bmRequestType.dataTransferDirection */
+#define HOST_TO_DEVICE (0)
+#define DEVICE_TO_HOST (1)
+
+/* bmRequestType.Type*/
+#define STANDARD_TYPE  (0)
+#define CLASS_TYPE     (1)
+#define VENDOR_TYPE    (2)
+#define RESERVED_TYPE  (3)
+
+/* bmRequestType.Recipient */
+#define DEVICE_RECIPIENT    (0)
+#define INTERFACE_RECIPIENT (1)
+#define ENDPOINT_RECIPIENT  (2)
+#define OTHER_RECIPIENT     (3)
+
+/* Descriptors */
+#define DESCRIPTOR_TYPE(wValue)  (wValue >> 8)
+#define DESCRIPTOR_INDEX(wValue) (wValue & 0xf)
+
+typedef struct {
+    struct {
+        uint8_t dataTransferDirection;
+        uint8_t Type;
+        uint8_t Recipient;
+    } bmRequestType;
+    uint8_t  bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+} SETUP_PACKET;
+
+typedef struct {
+    SETUP_PACKET setup;
+    uint8_t *ptr;
+    uint32_t remaining;
+    uint8_t direction;
+    bool zlp;
+    bool notify;
+} CONTROL_TRANSFER;
+
+typedef enum {ATTACHED, POWERED, DEFAULT, ADDRESS, CONFIGURED} DEVICE_STATE;
+
+typedef struct {
+    volatile DEVICE_STATE state;
+    uint8_t configuration;
+    bool suspended;
+} USB_DEVICE;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBEndpoints.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,34 @@
+/* USBEndpoints.h */
+/* USB endpoint configuration */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USBENDPOINTS_H
+#define USBENDPOINTS_H
+
+/* SETUP packet size */
+#define SETUP_PACKET_SIZE (8)
+
+/* Options flags for configuring endpoints */
+#define DEFAULT_OPTIONS     (0)
+#define SINGLE_BUFFERED     (1U << 0)
+#define ISOCHRONOUS         (1U << 1)
+#define RATE_FEEDBACK_MODE  (1U << 2) /* Interrupt endpoints only */
+
+/* Endpoint transfer status, for endpoints > 0 */
+typedef enum {
+    EP_COMPLETED,   /* Transfer completed */
+    EP_PENDING,     /* Transfer in progress */
+    EP_INVALID,     /* Invalid parameter */
+    EP_STALLED,     /* Endpoint stalled */
+} EP_STATUS;
+
+/* Include configuration for specific target */
+#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
+#include "USBEndpoints_LPC17_LPC23.h"
+#elif defined(TARGET_LPC11U24)
+#include "USBEndpoints_LPC11U.h"
+#else
+#error "Unknown target type"
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBEndpoints_LPC11U.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,51 @@
+/* USBEndpoints_LPC11U.h */
+/* Endpoint configuration for LPC11U */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#define NUMBER_OF_LOGICAL_ENDPOINTS (5)
+#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2)
+
+/* Define physical endpoint numbers */
+
+/*      Endpoint    No.     Type(s)       MaxPacket   DoubleBuffer  */
+/*      ----------------    ------------  ----------  ---           */
+#define EP0OUT      (0)  /* Control       64          No            */
+#define EP0IN       (1)  /* Control       64          No            */
+#define EP1OUT      (2)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP1IN       (3)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP2OUT      (4)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP2IN       (5)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP3OUT      (6)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP3IN       (7)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP4OUT      (8)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+#define EP4IN       (9)  /* Int/Bulk/Iso  64/64/1023  Yes           */
+
+/* Maximum Packet sizes */
+
+#define MAX_PACKET_SIZE_EP0 (64)
+#define MAX_PACKET_SIZE_EP1 (64) /* Int/Bulk */
+#define MAX_PACKET_SIZE_EP2 (64) /* Int/Bulk */
+#define MAX_PACKET_SIZE_EP3 (64) /* Int/Bulk */
+#define MAX_PACKET_SIZE_EP4 (64) /* Int/Bulk */
+
+#define MAX_PACKET_SIZE_EP1_ISO (1023) /* Isochronous */
+#define MAX_PACKET_SIZE_EP2_ISO (1023) /* Isochronous */
+#define MAX_PACKET_SIZE_EP3_ISO (1023) /* Isochronous */
+#define MAX_PACKET_SIZE_EP4_ISO (1023) /* Isochronous */
+
+/* Generic endpoints - intended to be portable accross devices */
+/* and be suitable for simple USB devices. */
+
+/* Bulk endpoint */
+#define EPBULK_OUT  (EP2OUT)
+#define EPBULK_IN   (EP2IN)
+/* Interrupt endpoint */
+#define EPINT_OUT   (EP1OUT)
+#define EPINT_IN    (EP1IN)
+/* Isochronous endpoint */
+#define EPISO_OUT   (EP3OUT)
+#define EPISO_IN    (EP3IN)
+
+#define MAX_PACKET_SIZE_EPBULK  (MAX_PACKET_SIZE_EP2)
+#define MAX_PACKET_SIZE_EPINT   (MAX_PACKET_SIZE_EP1)
+#define MAX_PACKET_SIZE_EPISO   (MAX_PACKET_SIZE_EP3_ISO)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBDevice/USBEndpoints_LPC17_LPC23.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,84 @@
+/* USBEndpoints_LPC17_LPC23.h */
+/* Endpoint configuration for LPC1768 and LPC2368 */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#define NUMBER_OF_LOGICAL_ENDPOINTS (16)
+#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2)
+
+/* Define physical endpoint numbers */
+
+/*      Endpoint    No.     Type(s)       MaxPacket   DoubleBuffer  */
+/*      ----------------    ------------  ----------  ---           */
+#define EP0OUT      (0)  /* Control       64          No            */
+#define EP0IN       (1)  /* Control       64          No            */
+#define EP1OUT      (2)  /* Interrupt     64          No            */
+#define EP1IN       (3)  /* Interrupt     64          No            */
+#define EP2OUT      (4)  /* Bulk          64          Yes           */
+#define EP2IN       (5)  /* Bulk          64          Yes           */
+#define EP3OUT      (6)  /* Isochronous   1023        Yes           */
+#define EP3IN       (7)  /* Isochronous   1023        Yes           */
+#define EP4OUT      (8)  /* Interrupt     64          No            */
+#define EP4IN       (9)  /* Interrupt     64          No            */
+#define EP5OUT      (10) /* Bulk          64          Yes           */
+#define EP5IN       (11) /* Bulk          64          Yes           */
+#define EP6OUT      (12) /* Isochronous   1023        Yes           */
+#define EP6IN       (13) /* Isochronous   1023        Yes           */
+#define EP7OUT      (14) /* Interrupt     64          No            */
+#define EP7IN       (15) /* Interrupt     64          No            */
+#define EP8OUT      (16) /* Bulk          64          Yes           */
+#define EP8IN       (17) /* Bulk          64          Yes           */
+#define EP9OUT      (18) /* Isochronous   1023        Yes           */
+#define EP9IN       (19) /* Isochronous   1023        Yes           */
+#define EP10OUT     (20) /* Interrupt     64          No            */
+#define EP10IN      (21) /* Interrupt     64          No            */
+#define EP11OUT     (22) /* Bulk          64          Yes           */
+#define EP11IN      (23) /* Bulk          64          Yes           */
+#define EP12OUT     (24) /* Isochronous   1023        Yes           */
+#define EP12IN      (25) /* Isochronous   1023        Yes           */
+#define EP13OUT     (26) /* Interrupt     64          No            */
+#define EP13IN      (27) /* Interrupt     64          No            */
+#define EP14OUT     (28) /* Bulk          64          Yes           */
+#define EP14IN      (29) /* Bulk          64          Yes           */
+#define EP15OUT     (30) /* Bulk          64          Yes           */
+#define EP15IN      (31) /* Bulk          64          Yes           */
+
+/* Maximum Packet sizes */
+
+#define MAX_PACKET_SIZE_EP0  (64)
+#define MAX_PACKET_SIZE_EP1  (16)
+#define MAX_PACKET_SIZE_EP2  (64)
+#define MAX_PACKET_SIZE_EP3  (64)
+#define MAX_PACKET_SIZE_EP4  (64)
+#define MAX_PACKET_SIZE_EP5  (64)
+#define MAX_PACKET_SIZE_EP6  (64)
+#define MAX_PACKET_SIZE_EP7  (64)
+#define MAX_PACKET_SIZE_EP8  (64)
+#define MAX_PACKET_SIZE_EP9  (64)
+#define MAX_PACKET_SIZE_EP10 (64)
+#define MAX_PACKET_SIZE_EP11 (64)
+#define MAX_PACKET_SIZE_EP12 (64)
+#define MAX_PACKET_SIZE_EP13 (64)
+#define MAX_PACKET_SIZE_EP14 (64)
+#define MAX_PACKET_SIZE_EP15 (64)
+
+/* Generic endpoints - intended to be portable accross devices */
+/* and be suitable for simple USB devices. */
+
+/* Interrupt endpoints */
+#define EPINT_OUT   (EP1OUT)
+#define EPINT_IN    (EP1IN)
+/* Bulk endpoints */
+#define EPBULK_OUT  (EP2OUT)
+#define EPBULK_IN   (EP2IN)
+/* Isochronous endpoints */
+//#define EPISO_OUT   (EP3OUT)
+//#define EPISO_IN    (EP3IN)
+
+/* MSC Bulk endpoints */
+#define MSCBULK_OUT  (EP3OUT)
+#define MSCBULK_IN   (EP3IN)
+
+#define MAX_PACKET_SIZE_EPINT   (MAX_PACKET_SIZE_EP1)
+#define MAX_PACKET_SIZE_EPBULK  (MAX_PACKET_SIZE_EP2)
+//#define MAX_PACKET_SIZE_EPISO   (MAX_PACKET_SIZE_EP3)
+#define MAX_PACKET_SIZE_MSCBULK  (MAX_PACKET_SIZE_EP3)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHID/USBHID.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,259 @@
+// USBHID.c
+// Human Interface Device (HID) class
+// Copyright (c) 2011 ARM Limited. All rights reserved.
+
+#include "stdint.h"
+#include "USBBusInterface.h"
+#include "USBHID.h"
+
+
+USBHID::USBHID(uint8_t output_report_length, uint8_t input_report_length, uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release)
+{
+    output_length = output_report_length;
+    input_length = input_report_length;
+}
+
+
+bool USBHID::send(HID_REPORT *report)
+{
+    return write(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
+}
+
+
+bool USBHID::read(HID_REPORT *report)
+{
+    uint16_t bytesRead = 0;
+    bool result;
+    result = USBDevice::read(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
+    if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
+        return false;
+    report->length = bytesRead;
+    return result;
+}
+
+
+bool USBHID::readNB(HID_REPORT *report)
+{
+    uint16_t bytesRead = 0;
+    bool result;
+    result = USBDevice::readNB(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
+    report->length = bytesRead;
+    if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
+        return false;
+    return result;
+}
+
+
+uint16_t USBHID::reportDescLength() {
+    reportDesc();
+    return reportLength;
+}
+
+
+
+//
+//  Route callbacks from lower layers to class(es)
+//
+
+
+// Called in ISR context
+// Called by USBDevice on Endpoint0 request
+// This is used to handle extensions to standard requests
+// and class specific requests
+// Return true if class handles this request
+bool USBHID::USBCallback_request() {
+    bool success = false;
+    CONTROL_TRANSFER * transfer = getTransferPtr();
+    uint8_t *hidDescriptor;
+
+    // Process additional standard requests
+
+    if ((transfer->setup.bmRequestType.Type == STANDARD_TYPE))
+    {
+        switch (transfer->setup.bRequest)
+        {
+            case GET_DESCRIPTOR:
+                switch (DESCRIPTOR_TYPE(transfer->setup.wValue))
+                {
+                    case REPORT_DESCRIPTOR:
+                        if ((reportDesc() != NULL) \
+                            && (reportDescLength() != 0))
+                        {
+                            transfer->remaining = reportDescLength();
+                            transfer->ptr = reportDesc();
+                            transfer->direction = DEVICE_TO_HOST;
+                            success = true;
+                        }
+                        break;
+                    case HID_DESCRIPTOR:
+                            // Find the HID descriptor, after the configuration descriptor
+                            hidDescriptor = findDescriptor(HID_DESCRIPTOR);
+                            if (hidDescriptor != NULL)
+                            {
+                                transfer->remaining = HID_DESCRIPTOR_LENGTH;
+                                transfer->ptr = hidDescriptor;
+                                transfer->direction = DEVICE_TO_HOST;
+                                success = true;
+                            }
+                            break;
+                     
+                    default:
+                        break;
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    // Process class-specific requests
+
+    if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
+    {
+        switch (transfer->setup.bRequest)
+        {
+             case SET_REPORT:
+                // First byte will be used for report ID
+                outputReport.data[0] = transfer->setup.wValue & 0xff;
+                outputReport.length = transfer->setup.wLength + 1;
+
+                transfer->remaining = sizeof(outputReport.data) - 1;
+                transfer->ptr = &outputReport.data[1];
+                transfer->direction = HOST_TO_DEVICE;
+                transfer->notify = true;
+                success = true;
+            default:
+                break;
+        }
+    }
+
+    return success;
+}
+
+
+// Called in ISR context
+// Called by USBDevice on Endpoint0 request completion
+// if the 'notify' flag has been set to true
+// In this case it is used to indicate that a HID report has
+// been received from the host on endpoint 0
+void USBHID::USBCallback_requestCompleted() {
+    HID_callbackSetReport(&outputReport);
+}
+
+#define DEFAULT_CONFIGURATION (1)
+
+
+// Called in ISR context
+// Set configuration. Return false if the
+// configuration is not supported
+bool USBHID::USBCallback_setConfiguration(uint8_t configuration) {
+    if (configuration != DEFAULT_CONFIGURATION) {
+        return false;
+    }
+
+    // Configure endpoints > 0
+    addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
+    addEndpoint(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
+
+    // We activate the endpoint to be able to recceive data
+    readStart(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
+    return true;
+}
+
+uint8_t * USBHID::stringIinterfaceDesc() {
+    static uint8_t stringIinterfaceDescriptor[] = {
+        0x08,               //bLength
+        STRING_DESCRIPTOR,  //bDescriptorType 0x03
+        'H',0,'I',0,'D',0,  //bString iInterface - HID
+    };
+    return stringIinterfaceDescriptor;
+}
+
+uint8_t * USBHID::stringIproductDesc() {
+    static uint8_t stringIproductDescriptor[] = {
+        0x16,                                                       //bLength
+        STRING_DESCRIPTOR,                                          //bDescriptorType 0x03
+        'H',0,'I',0,'D',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 //bString iProduct - HID device
+    };
+    return stringIproductDescriptor;
+}
+
+
+
+uint8_t * USBHID::reportDesc() {
+    static uint8_t reportDescriptor[] = {
+        0x06, LSB(0xFFAB), MSB(0xFFAB),
+        0x0A, LSB(0x0200), MSB(0x0200),
+        0xA1, 0x01,         // Collection 0x01
+        0x75, 0x08,         // report size = 8 bits
+        0x15, 0x00,         // logical minimum = 0
+        0x26, 0xFF, 0x00,   // logical maximum = 255
+        0x95, input_length,           // report count
+        0x09, 0x01,         // usage
+        0x81, 0x02,         // Input (array)
+        0x95, output_length,           // report count
+        0x09, 0x02,         // usage
+        0x91, 0x02,         // Output (array)
+        0xC0                // end collection
+
+    };
+    reportLength = sizeof(reportDescriptor);
+    return reportDescriptor;
+}
+
+#define DEFAULT_CONFIGURATION (1)
+#define TOTAL_DESCRIPTOR_LENGTH ((1 * CONFIGURATION_DESCRIPTOR_LENGTH) \
+                               + (1 * INTERFACE_DESCRIPTOR_LENGTH) \
+                               + (1 * HID_DESCRIPTOR_LENGTH) \
+                               + (2 * ENDPOINT_DESCRIPTOR_LENGTH))
+
+uint8_t * USBHID::configurationDesc() {
+    static uint8_t configurationDescriptor[] = {
+        CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
+        CONFIGURATION_DESCRIPTOR,       // bDescriptorType
+        LSB(TOTAL_DESCRIPTOR_LENGTH),   // wTotalLength (LSB)
+        MSB(TOTAL_DESCRIPTOR_LENGTH),   // wTotalLength (MSB)
+        0x01,                           // bNumInterfaces
+        DEFAULT_CONFIGURATION,          // bConfigurationValue
+        0x00,                           // iConfiguration
+        C_RESERVED | C_SELF_POWERED,    // bmAttributes
+        C_POWER(0),                     // bMaxPower
+
+        INTERFACE_DESCRIPTOR_LENGTH,    // bLength
+        INTERFACE_DESCRIPTOR,           // bDescriptorType
+        0x00,                           // bInterfaceNumber
+        0x00,                           // bAlternateSetting
+        0x02,                           // bNumEndpoints
+        HID_CLASS,                      // bInterfaceClass
+        HID_SUBCLASS_NONE,              // bInterfaceSubClass
+        HID_PROTOCOL_NONE,              // bInterfaceProtocol
+        0x00,                           // iInterface
+
+        HID_DESCRIPTOR_LENGTH,          // bLength
+        HID_DESCRIPTOR,                 // bDescriptorType
+        LSB(HID_VERSION_1_11),          // bcdHID (LSB)
+        MSB(HID_VERSION_1_11),          // bcdHID (MSB)
+        0x00,                           // bCountryCode
+        0x01,                           // bNumDescriptors
+        REPORT_DESCRIPTOR,              // bDescriptorType
+        LSB(this->reportDescLength()),  // wDescriptorLength (LSB)
+        MSB(this->reportDescLength()),  // wDescriptorLength (MSB)
+
+        ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+        ENDPOINT_DESCRIPTOR,            // bDescriptorType
+        PHY_TO_DESC(EPINT_IN),          // bEndpointAddress
+        E_INTERRUPT,                    // bmAttributes
+        LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+        10,                             // bInterval (milliseconds)
+
+        ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+        ENDPOINT_DESCRIPTOR,            // bDescriptorType
+        PHY_TO_DESC(EPINT_OUT),          // bEndpointAddress
+        E_INTERRUPT,                    // bmAttributes
+        LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+        MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+        10,                             // bInterval (milliseconds)
+    };
+    return configurationDescriptor;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHID/USBHID.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,158 @@
+/* USBHID.h */
+/* Human Interface Device (HID) class */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USB_HID_H
+#define USB_HID_H
+
+/* These headers are included for child class. */
+#include "USBEndpoints.h"
+#include "USBDescriptor.h"
+#include "USBDevice_Types.h"
+
+#include "USBHID_Types.h"
+#include "USBDevice.h"
+
+
+/**
+ * USBHID example
+ * @code
+ * #include "mbed.h"
+ * #include "USBHID.h"
+ *
+ * USBHID hid;
+ * HID_REPORT recv;
+ * BusOut leds(LED1,LED2,LED3,LED4);
+ *
+ * int main(void) {
+ *    while (1) {
+ *        hid.read(&recv);
+ *        leds = recv.data[0];
+ *    }
+ * }
+ * @endcode
+ */
+
+class USBHID: public USBDevice {
+public:
+
+    /**
+    * Constructor
+    *
+    * @param output_report_length Maximum length of a sent report (up to 64 bytes) (default: 64 bytes)
+    * @param input_report_length Maximum length of a received report (up to 64 bytes) (default: 64 bytes)
+    * @param vendor_id Your vendor_id
+    * @param product_id Your product_id
+    * @param product_release Your preoduct_release
+    */
+    USBHID(uint8_t output_report_length = 64, uint8_t input_report_length = 64, uint16_t vendor_id = 0x1234, uint16_t product_id = 0x0006, uint16_t product_release = 0x0001);
+
+
+    /**
+    * Send a Report
+    *
+    * @param report Report which will be sent (a report is defined by all data and the length)
+    * @returns true if successful
+    */
+    bool send(HID_REPORT *report);
+    
+    /**
+    * Read a report: blocking
+    *
+    * @param report pointer to the report to fill
+    * @returns true if successful
+    */
+    bool read(HID_REPORT * report);
+    
+    /**
+    * Read a report: non blocking
+    *
+    * @param report pointer to the report to fill
+    * @returns true if successful
+    */
+    bool readNB(HID_REPORT * report);
+
+    /*
+    * Get the Report descriptor
+    *
+    * @returns pointer to the report descriptor
+    */
+    virtual uint8_t * reportDesc();
+
+    /*
+    * Get the length of the report descriptor
+    *
+    * @returns the length of the report descriptor
+    */
+    virtual uint16_t reportDescLength();
+
+    /*
+    * Get string product descriptor
+    *
+    * @returns pointer to the string product descriptor
+    */
+    virtual uint8_t * stringIproductDesc();
+    
+    /*
+    * Get string interface descriptor
+    *
+    * @returns pointer to the string interface descriptor
+    */
+    virtual uint8_t * stringIinterfaceDesc();
+    
+    /*
+    * Get configuration descriptor
+    *
+    * @returns pointer to the configuration descriptor
+    */
+    virtual uint8_t * configurationDesc();
+
+
+    /*
+    * HID Report received by SET_REPORT request. Warning: Called in ISR context
+    * First byte of data will be the report ID
+    *
+    * @param report Data and length received
+    */
+    virtual void HID_callbackSetReport(HID_REPORT *report){};
+
+
+    /*
+    * Called by USBDevice on Endpoint0 request. Warning: Called in ISR context
+    * This is used to handle extensions to standard requests
+    * and class specific requests
+    *
+    * @returns true if class handles this request
+    */
+    virtual bool USBCallback_request();
+
+    /*
+    * Called by USBDevice on Endpoint0 request completion
+    * if the 'notify' flag has been set to true. Warning: Called in ISR context
+    *
+    * In this case it is used to indicate that a HID report has
+    * been received from the host on endpoint 0
+    */
+    virtual void USBCallback_requestCompleted();
+
+    /*
+    * Called by USBDevice layer. Set configuration of the device.
+    * For instance, you can add all endpoints that you need on this function.
+    *
+    * @param configuration Number of the configuration
+    * @returns true if class handles this request
+    */
+    virtual bool USBCallback_setConfiguration(uint8_t configuration);
+
+
+
+protected:
+    uint16_t reportLength;
+
+private:
+    HID_REPORT outputReport;
+    uint8_t output_length;
+    uint8_t input_length;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHID/USBHID_Types.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,77 @@
+/* USBClass_HID_Types.h */
+/* USB HID class type definitions, conversions and constants */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USBCLASS_HID_TYPES
+#define USBCLASS_HID_TYPES
+
+#include <stdint.h>
+
+/* */
+#define HID_VERSION_1_11    (0x0111)
+
+/* HID Class */
+#define HID_CLASS           (3)
+#define HID_SUBCLASS_NONE   (0)
+#define HID_PROTOCOL_NONE   (0)
+
+/* Descriptors */
+#define HID_DESCRIPTOR          (33)
+#define HID_DESCRIPTOR_LENGTH   (0x09)
+#define REPORT_DESCRIPTOR       (34)
+
+/* Class requests */
+#define GET_REPORT (0x1)
+#define GET_IDLE   (0x2)
+#define SET_REPORT (0x9)
+#define SET_IDLE   (0xa)
+
+/* HID Class Report Descriptor */
+/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
+/* of data as per HID Class standard */
+
+/* Main items */
+#define INPUT(size)             (0x80 | size)
+#define OUTPUT(size)            (0x90 | size)
+#define FEATURE(size)           (0xb0 | size)
+#define COLLECTION(size)        (0xa0 | size)
+#define END_COLLECTION(size)    (0xc0 | size)
+
+/* Global items */
+#define USAGE_PAGE(size)        (0x04 | size)
+#define LOGICAL_MINIMUM(size)   (0x14 | size)
+#define LOGICAL_MAXIMUM(size)   (0x24 | size)
+#define PHYSICAL_MINIMUM(size)  (0x34 | size)
+#define PHYSICAL_MAXIMUM(size)  (0x44 | size)
+#define UNIT_EXPONENT(size)     (0x54 | size)
+#define UNIT(size)              (0x64 | size)
+#define REPORT_SIZE(size)       (0x74 | size)
+#define REPORT_ID(size)         (0x84 | size)
+#define REPORT_COUNT(size)      (0x94 | size)
+#define PUSH(size)              (0xa4 | size)
+#define POP(size)               (0xb4 | size)
+
+/* Local items */
+#define USAGE(size)                 (0x08 | size)
+#define USAGE_MINIMUM(size)         (0x18 | size)
+#define USAGE_MAXIMUM(size)         (0x28 | size)
+#define DESIGNATOR_INDEX(size)      (0x38 | size)
+#define DESIGNATOR_MINIMUM(size)    (0x48 | size)
+#define DESIGNATOR_MAXIMUM(size)    (0x58 | size)
+#define STRING_INDEX(size)          (0x78 | size)
+#define STRING_MINIMUM(size)        (0x88 | size)
+#define STRING_MAXIMUM(size)        (0x98 | size)
+#define DELIMITER(size)             (0xa8 | size)
+
+/* HID Report */
+/* Where report IDs are used the first byte of 'data' will be the */
+/* report ID and 'length' will include this report ID byte. */
+
+#define MAX_HID_REPORT_SIZE (64)
+
+typedef struct {
+    uint32_t length;
+    uint8_t data[MAX_HID_REPORT_SIZE];
+} HID_REPORT;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHID/USBKeyboard.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,448 @@
+// USBKeyboard.c
+// USB device example: Standard keyboard
+// Copyright (c) 2011 ARM Limited. All rights reserved.
+
+#include "stdint.h"
+
+#include "USBKeyboard.h"
+
+#define REPORT_ID_KEYBOARD 1
+#define REPORT_ID_VOLUME   3
+
+
+typedef struct {
+    unsigned char usage;
+    unsigned char modifier;
+} KEYMAP;
+
+#ifdef US_KEYBOARD
+/* US keyboard (as HID standard) */
+#define KEYMAP_SIZE (145)
+const KEYMAP keymap[KEYMAP_SIZE] = {
+{0, 0},             /* NUL */
+{0, 0},             /* SOH */
+{0, 0},             /* STX */
+{0, 0},             /* ETX */
+{0, 0},             /* EOT */
+{0, 0},             /* ENQ */
+{0, 0},             /* ACK */
+{0, 0},             /* BEL */
+{0x2a, 0},          /* BS  */  /* Keyboard Delete (Backspace) */
+{0x2b, 0},          /* TAB */  /* Keyboard Tab */
+{0x28, 0},          /* LF  */  /* Keyboard Return (Enter) */
+{0, 0},             /* VT  */
+{0, 0},             /* FF  */
+{0, 0},             /* CR  */
+{0, 0},             /* SO  */
+{0, 0},             /* SI  */
+{0, 0},             /* DEL */
+{0, 0},             /* DC1 */
+{0, 0},             /* DC2 */
+{0, 0},             /* DC3 */
+{0, 0},             /* DC4 */
+{0, 0},             /* NAK */
+{0, 0},             /* SYN */
+{0, 0},             /* ETB */
+{0, 0},             /* CAN */
+{0, 0},             /* EM  */
+{0, 0},             /* SUB */
+{0, 0},             /* ESC */
+{0, 0},             /* FS  */
+{0, 0},             /* GS  */
+{0, 0},             /* RS  */
+{0, 0},             /* US  */
+{0x2c, 0},          /*   */
+{0x1e, KEY_SHIFT},      /* ! */
+{0x34, KEY_SHIFT},      /* " */
+{0x20, KEY_SHIFT},      /* # */
+{0x21, KEY_SHIFT},      /* $ */
+{0x22, KEY_SHIFT},      /* % */
+{0x24, KEY_SHIFT},      /* & */
+{0x34, 0},          /* ' */
+{0x26, KEY_SHIFT},      /* ( */
+{0x27, KEY_SHIFT},      /* ) */
+{0x25, KEY_SHIFT},      /* * */
+{0x2e, KEY_SHIFT},      /* + */
+{0x36, 0},          /* , */
+{0x2d, 0},          /* - */
+{0x37, 0},          /* . */
+{0x38, 0},          /* / */
+{0x27, 0},          /* 0 */
+{0x1e, 0},          /* 1 */
+{0x1f, 0},          /* 2 */
+{0x20, 0},          /* 3 */
+{0x21, 0},          /* 4 */
+{0x22, 0},          /* 5 */
+{0x23, 0},          /* 6 */
+{0x24, 0},          /* 7 */
+{0x25, 0},          /* 8 */
+{0x26, 0},          /* 9 */
+{0x33, KEY_SHIFT},      /* : */
+{0x33, 0},          /* ; */
+{0x36, KEY_SHIFT},      /* < */
+{0x2e, 0},          /* = */
+{0x37, KEY_SHIFT},      /* > */
+{0x38, KEY_SHIFT},      /* ? */
+{0x1f, KEY_SHIFT},      /* @ */
+{0x04, KEY_SHIFT},      /* A */
+{0x05, KEY_SHIFT},      /* B */
+{0x06, KEY_SHIFT},      /* C */
+{0x07, KEY_SHIFT},      /* D */
+{0x08, KEY_SHIFT},      /* E */
+{0x09, KEY_SHIFT},      /* F */
+{0x0a, KEY_SHIFT},      /* G */
+{0x0b, KEY_SHIFT},      /* H */
+{0x0c, KEY_SHIFT},      /* I */
+{0x0d, KEY_SHIFT},      /* J */
+{0x0e, KEY_SHIFT},      /* K */
+{0x0f, KEY_SHIFT},      /* L */
+{0x10, KEY_SHIFT},      /* M */
+{0x11, KEY_SHIFT},      /* N */
+{0x12, KEY_SHIFT},      /* O */
+{0x13, KEY_SHIFT},      /* P */
+{0x14, KEY_SHIFT},      /* Q */
+{0x15, KEY_SHIFT},      /* R */
+{0x16, KEY_SHIFT},      /* S */
+{0x17, KEY_SHIFT},      /* T */
+{0x18, KEY_SHIFT},      /* U */
+{0x19, KEY_SHIFT},      /* V */
+{0x1a, KEY_SHIFT},      /* W */
+{0x1b, KEY_SHIFT},      /* X */
+{0x1c, KEY_SHIFT},      /* Y */
+{0x1d, KEY_SHIFT},      /* Z */
+{0x2f, 0},          /* [ */
+{0x31, 0},          /* \ */
+{0x30, 0},          /* ] */
+{0x23, KEY_SHIFT},      /* ^ */
+{0x2d, KEY_SHIFT},      /* _ */
+{0x35, 0},          /* ` */
+{0x04, 0},          /* a */
+{0x05, 0},          /* b */
+{0x06, 0},          /* c */
+{0x07, 0},          /* d */
+{0x08, 0},          /* e */
+{0x09, 0},          /* f */
+{0x0a, 0},          /* g */
+{0x0b, 0},          /* h */
+{0x0c, 0},          /* i */
+{0x0d, 0},          /* j */
+{0x0e, 0},          /* k */
+{0x0f, 0},          /* l */
+{0x10, 0},          /* m */
+{0x11, 0},          /* n */
+{0x12, 0},          /* o */
+{0x13, 0},          /* p */
+{0x14, 0},          /* q */
+{0x15, 0},          /* r */
+{0x16, 0},          /* s */
+{0x17, 0},          /* t */
+{0x18, 0},          /* u */
+{0x19, 0},          /* v */
+{0x1a, 0},          /* w */
+{0x1b, 0},          /* x */
+{0x1c, 0},          /* y */
+{0x1d, 0},          /* z */
+{0x2f, KEY_SHIFT},      /* { */
+{0x31, KEY_SHIFT},      /* | */
+{0x30, KEY_SHIFT},      /* } */
+{0x35, KEY_SHIFT},      /* ~ */
+{0,0},              /* DEL */
+
+{0x3a, 0},          /* F1 */
+{0x3b, 0},          /* F2 */
+{0x3c, 0},          /* F3 */
+{0x3d, 0},          /* F4 */
+{0x3e, 0},          /* F5 */
+{0x3f, 0},          /* F6 */
+{0x40, 0},          /* F7 */
+{0x41, 0},          /* F8 */
+{0x42, 0},          /* F9 */
+{0x43, 0},          /* F10 */
+{0x44, 0},          /* F11 */
+{0x45, 0},          /* F12 */
+
+{0x46, 0},          /* PRINT_SCREEN */
+{0x49, 0},          /* INSERT */
+{0x4a, 0},          /* HOME */
+{0x4b, 0},          /* PAGE_UP */
+{0x4e, 0},          /* PAGE_DOWN */
+};
+
+#else
+/* UK keyboard */
+#define KEYMAP_SIZE (145)
+const KEYMAP keymap[KEYMAP_SIZE] = {
+{0, 0},             /* NUL */
+{0, 0},             /* SOH */
+{0, 0},             /* STX */
+{0, 0},             /* ETX */
+{0, 0},             /* EOT */
+{0, 0},             /* ENQ */
+{0, 0},             /* ACK */
+{0, 0},             /* BEL */
+{0x2a, 0},          /* BS  */  /* Keyboard Delete (Backspace) */
+{0x2b, 0},          /* TAB */  /* Keyboard Tab */
+{0x28, 0},          /* LF  */  /* Keyboard Return (Enter) */
+{0, 0},             /* VT  */
+{0, 0},             /* FF  */
+{0, 0},             /* CR  */
+{0, 0},             /* SO  */
+{0, 0},             /* SI  */
+{0, 0},             /* DEL */
+{0, 0},             /* DC1 */
+{0, 0},             /* DC2 */
+{0, 0},             /* DC3 */
+{0, 0},             /* DC4 */
+{0, 0},             /* NAK */
+{0, 0},             /* SYN */
+{0, 0},             /* ETB */
+{0, 0},             /* CAN */
+{0, 0},             /* EM  */
+{0, 0},             /* SUB */
+{0, 0},             /* ESC */
+{0, 0},             /* FS  */
+{0, 0},             /* GS  */
+{0, 0},             /* RS  */
+{0, 0},             /* US  */
+{0x2c, 0},          /*   */
+{0x1e, KEY_SHIFT},      /* ! */
+{0x1f, KEY_SHIFT},      /* " */
+{0x32, 0},          /* # */
+{0x21, KEY_SHIFT},      /* $ */
+{0x22, KEY_SHIFT},      /* % */
+{0x24, KEY_SHIFT},      /* & */
+{0x34, 0},          /* ' */
+{0x26, KEY_SHIFT},      /* ( */
+{0x27, KEY_SHIFT},      /* ) */
+{0x25, KEY_SHIFT},      /* * */
+{0x2e, KEY_SHIFT},      /* + */
+{0x36, 0},          /* , */
+{0x2d, 0},          /* - */
+{0x37, 0},          /* . */
+{0x38, 0},          /* / */
+{0x27, 0},          /* 0 */
+{0x1e, 0},          /* 1 */
+{0x1f, 0},          /* 2 */
+{0x20, 0},          /* 3 */
+{0x21, 0},          /* 4 */
+{0x22, 0},          /* 5 */
+{0x23, 0},          /* 6 */
+{0x24, 0},          /* 7 */
+{0x25, 0},          /* 8 */
+{0x26, 0},          /* 9 */
+{0x33, KEY_SHIFT},      /* : */
+{0x33, 0},          /* ; */
+{0x36, KEY_SHIFT},      /* < */
+{0x2e, 0},          /* = */
+{0x37, KEY_SHIFT},      /* > */
+{0x38, KEY_SHIFT},      /* ? */
+{0x34, KEY_SHIFT},      /* @ */
+{0x04, KEY_SHIFT},      /* A */
+{0x05, KEY_SHIFT},      /* B */
+{0x06, KEY_SHIFT},      /* C */
+{0x07, KEY_SHIFT},      /* D */
+{0x08, KEY_SHIFT},      /* E */
+{0x09, KEY_SHIFT},      /* F */
+{0x0a, KEY_SHIFT},      /* G */
+{0x0b, KEY_SHIFT},      /* H */
+{0x0c, KEY_SHIFT},      /* I */
+{0x0d, KEY_SHIFT},      /* J */
+{0x0e, KEY_SHIFT},      /* K */
+{0x0f, KEY_SHIFT},      /* L */
+{0x10, KEY_SHIFT},      /* M */
+{0x11, KEY_SHIFT},      /* N */
+{0x12, KEY_SHIFT},      /* O */
+{0x13, KEY_SHIFT},      /* P */
+{0x14, KEY_SHIFT},      /* Q */
+{0x15, KEY_SHIFT},      /* R */
+{0x16, KEY_SHIFT},      /* S */
+{0x17, KEY_SHIFT},      /* T */
+{0x18, KEY_SHIFT},      /* U */
+{0x19, KEY_SHIFT},      /* V */
+{0x1a, KEY_SHIFT},      /* W */
+{0x1b, KEY_SHIFT},      /* X */
+{0x1c, KEY_SHIFT},      /* Y */
+{0x1d, KEY_SHIFT},      /* Z */
+{0x2f, 0},          /* [ */
+{0x64, 0},          /* \ */
+{0x30, 0},          /* ] */
+{0x23, KEY_SHIFT},      /* ^ */
+{0x2d, KEY_SHIFT},      /* _ */
+{0x35, 0},          /* ` */
+{0x04, 0},          /* a */
+{0x05, 0},          /* b */
+{0x06, 0},          /* c */
+{0x07, 0},          /* d */
+{0x08, 0},          /* e */
+{0x09, 0},          /* f */
+{0x0a, 0},          /* g */
+{0x0b, 0},          /* h */
+{0x0c, 0},          /* i */
+{0x0d, 0},          /* j */
+{0x0e, 0},          /* k */
+{0x0f, 0},          /* l */
+{0x10, 0},          /* m */
+{0x11, 0},          /* n */
+{0x12, 0},          /* o */
+{0x13, 0},          /* p */
+{0x14, 0},          /* q */
+{0x15, 0},          /* r */
+{0x16, 0},          /* s */
+{0x17, 0},          /* t */
+{0x18, 0},          /* u */
+{0x19, 0},          /* v */
+{0x1a, 0},          /* w */
+{0x1b, 0},          /* x */
+{0x1c, 0},          /* y */
+{0x1d, 0},          /* z */
+{0x2f, KEY_SHIFT},      /* { */
+{0x64, KEY_SHIFT},      /* | */
+{0x30, KEY_SHIFT},      /* } */
+{0x32, KEY_SHIFT},      /* ~ */
+{0,0},             /* DEL */
+
+{0x3a, 0},          /* F1 */
+{0x3b, 0},          /* F2 */
+{0x3c, 0},          /* F3 */
+{0x3d, 0},          /* F4 */
+{0x3e, 0},          /* F5 */
+{0x3f, 0},          /* F6 */
+{0x40, 0},          /* F7 */
+{0x41, 0},          /* F8 */
+{0x42, 0},          /* F9 */
+{0x43, 0},          /* F10 */
+{0x44, 0},          /* F11 */
+{0x45, 0},          /* F12 */
+
+{0x46, 0},          /* PRINT_SCREEN */
+{0x49, 0},          /* INSERT */
+{0x4a, 0},          /* HOME */
+{0x4b, 0},          /* PAGE_UP */
+{0x4e, 0},          /* PAGE_DOWN */
+};
+#endif
+
+uint8_t * USBKeyboard::reportDesc() {
+    static uint8_t reportDescriptor[] = {
+        USAGE_PAGE(1), 0x01,                    // Generic Desktop
+        USAGE(1), 0x06,                         // Keyboard
+        COLLECTION(1), 0x01,                    // Application
+        REPORT_ID(1),       REPORT_ID_KEYBOARD,
+
+        USAGE_PAGE(1), 0x07,                    // Key Codes
+        USAGE_MINIMUM(1), 0xE0,
+        USAGE_MAXIMUM(1), 0xE7,
+        LOGICAL_MINIMUM(1), 0x00,
+        LOGICAL_MAXIMUM(1), 0x01,
+        REPORT_SIZE(1), 0x01,
+        REPORT_COUNT(1), 0x08,
+        INPUT(1), 0x02,                         // Data, Variable, Absolute
+        REPORT_COUNT(1), 0x01,
+        REPORT_SIZE(1), 0x08,
+        INPUT(1), 0x01,                         // Constant
+        REPORT_COUNT(1), 0x05,
+        REPORT_SIZE(1), 0x01,
+
+
+        USAGE_PAGE(1), 0x08,                    // LEDs
+        USAGE_MINIMUM(1), 0x01,
+        USAGE_MAXIMUM(1), 0x05,
+        OUTPUT(1), 0x02,                        // Data, Variable, Absolute
+        REPORT_COUNT(1), 0x01,
+        REPORT_SIZE(1), 0x03,
+        OUTPUT(1), 0x01,                        // Constant
+        REPORT_COUNT(1), 0x06,
+        REPORT_SIZE(1), 0x08,
+        LOGICAL_MINIMUM(1), 0x00,
+        LOGICAL_MAXIMUM(1), 0x65,
+
+
+        USAGE_PAGE(1), 0x07,                    // Key Codes
+        USAGE_MINIMUM(1), 0x00,
+        USAGE_MAXIMUM(1), 0x65,
+        INPUT(1), 0x00,                         // Data, Array
+        END_COLLECTION(0),
+
+        // Media Control
+        USAGE_PAGE(1), 0x0C,
+        USAGE(1), 0x01,
+        COLLECTION(1), 0x01,
+        REPORT_ID(1), REPORT_ID_VOLUME,
+        USAGE_PAGE(1), 0x0C,
+        LOGICAL_MINIMUM(1), 0x00,
+        LOGICAL_MAXIMUM(1), 0x01,
+        REPORT_SIZE(1), 0x01,
+        REPORT_COUNT(1), 0x07,
+        USAGE(1), 0xB5,             // Next Track
+        USAGE(1), 0xB6,             // Previous Track
+        USAGE(1), 0xB7,             // Stop
+        USAGE(1), 0xCD,             // Play / Pause
+        USAGE(1), 0xE2,             // Mute
+        USAGE(1), 0xE9,             // Volume Up
+        USAGE(1), 0xEA,             // Volume Down
+        INPUT(1), 0x02,             // Input (Data, Variable, Absolute)
+        REPORT_COUNT(1), 0x01,
+        INPUT(1), 0x01,
+        END_COLLECTION(0),
+
+    };
+    reportLength = sizeof(reportDescriptor);
+    return reportDescriptor;
+}
+
+int USBKeyboard::_putc(int c) {
+    return keyCode(c, keymap[c].modifier);
+}
+
+bool USBKeyboard::keyCode(uint8_t key, uint8_t modifier) {
+    // Send a simulated keyboard keypress. Returns true if successful.
+
+    HID_REPORT report;
+
+    report.data[0] = REPORT_ID_KEYBOARD;
+    report.data[1] = modifier;
+    report.data[2] = 0;
+    report.data[3] = keymap[key].usage;
+    report.data[4] = 0;
+    report.data[5] = 0;
+    report.data[6] = 0;
+    report.data[7] = 0;
+    report.data[8] = 0;
+
+    report.length = 9;
+
+    if (!send(&report)) {
+        return false;
+    }
+
+    report.data[1] = 0;
+    report.data[3] = 0;
+
+    if (!send(&report)) {
+        return false;
+    }
+
+    return true;
+
+}
+
+
+bool USBKeyboard::mediaControl(MEDIA_KEY key) {
+    HID_REPORT report;
+
+    report.data[0] = REPORT_ID_VOLUME;
+    report.data[1] = (1 << key) & 0x7f;
+
+    report.length = 2;
+
+    send(&report);
+    
+    report.data[0] = REPORT_ID_VOLUME;
+    report.data[1] = 0;
+
+    report.length = 2;
+
+    return send(&report);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHID/USBKeyboard.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,130 @@
+/* USBKeyboard.h */
+/* USB device example: Standard keyboard */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USBKEYBOARD_H
+#define USBKEYBOARD_H
+
+#include "USBHID.h"
+#include "Stream.h"
+
+/* Modifiers */
+enum MODIFIER_KEY
+{
+    KEY_CTRL = 1,
+    KEY_SHIFT = 2,
+    KEY_ALT = 4,
+};
+
+
+enum MEDIA_KEY
+{
+    KEY_NEXT_TRACK,     /*!< next Track Button */
+    KEY_PREVIOUS_TRACK, /*!< Previous track Button */
+    KEY_STOP,           /*!< Stop Button */
+    KEY_PLAY_PAUSE,     /*!< Play/Pause Button */
+    KEY_MUTE,           /*!< Mute Button */
+    KEY_VOLUME_UP,      /*!< Volume Up Button */
+    KEY_VOLUME_DOWN,    /*!< Volume Down Button */
+};
+
+enum FUNCTION_KEY
+{
+    KEY_F1 = 128,   /* F1 key */
+    KEY_F2,         /* F2 key */
+    KEY_F3,         /* F3 key */
+    KEY_F4,         /* F4 key */
+    KEY_F5,         /* F5 key */
+    KEY_F6,         /* F6 key */
+    KEY_F7,         /* F7 key */
+    KEY_F8,         /* F8 key */
+    KEY_F9,         /* F9 key */
+    KEY_F10,        /* F10 key */
+    KEY_F11,        /* F11 key */
+    KEY_F12,        /* F12 key */
+    KEY_PRINT_SCREEN,   /* Print Screen key */
+    KEY_INSERT,         /* Insert key */
+    KEY_HOME,           /* Home key */
+    KEY_PAGE_UP,        /* Page Up key */
+    KEY_PAGE_DOWN,      /* Page Down key */
+};
+
+/** 
+ * USBKeyboard example
+ * @code
+ *
+ * #include "mbed.h"
+ * #include "USBKeyboard.h"
+ *
+ * USBKeyboard key;
+ * 
+ * int main(void)
+ * {
+ *   while (1)
+ *   {
+ *       key.printf("Hello World\r\n");
+ *       wait(1);
+ *   }
+ * }
+ *
+ * @endcode
+ */
+class USBKeyboard: public USBHID, public Stream
+{
+    public:
+    
+        /**
+        *   Constructor
+        *
+        * @param vendor_id Your vendor_id (default: 0x1234)
+        * @param product_id Your product_id (default: 0x0001)
+        * @param product_release Your preoduct_release (default: 0x0001)
+        *
+        */
+        USBKeyboard(uint16_t vendor_id = 0x1234, uint16_t product_id = 0x0003, uint16_t product_release = 0x0001): USBHID(0, 0, vendor_id, product_id, product_release){};
+        
+        /**
+        * To send a character defined by a modifier(CTRL, SHIFT, ALT) and the key 
+        *
+        * @code
+        * //To send CTRL + s (save)
+        *  keyboard.keyCode('s', KEY_CTRL);
+        * @endcode
+        *
+        * @param modifier bit 0: KEY_CTRL, bit 1: KEY_SHIFT, bit 2: KEY_ALT (default: 0)
+        * @param key character to send
+        * @returns true if there is no error, false otherwise
+        */
+        bool keyCode(uint8_t key, uint8_t modifier = 0);
+        
+        /**
+        * Send a character
+        *
+        * @param c character to be sent
+        * @returns true if there is no error, false otherwise
+        */
+        virtual int _putc(int c);
+        
+        /**
+        * Control media keys
+        *
+        * @param key media key pressed (KEY_NEXT_TRACK, KEY_PREVIOUS_TRACK, KEY_STOP, KEY_PLAY_PAUSE, KEY_MUTE, KEY_VOLUME_UP, KEY_VOLUME_DOWN)
+        * @returns true if there is no error, false otherwise
+        */
+        bool mediaControl(MEDIA_KEY key);
+        
+        /*
+        * To define the report descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
+        *
+        * @returns pointer to the report descriptor
+        */
+        virtual uint8_t * reportDesc();
+        
+   private:
+        //dummy otherwise it doesn,t compile (we must define all methods of an abstract class)
+        virtual int _getc() { return -1;}
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHID/USBMouse.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,176 @@
+// USBMouse.c
+// USB device example: Relative mouse
+// Copyright (c) 2011 ARM Limited. All rights reserved.
+
+#include "stdint.h"
+#include "USBMouse.h"
+
+bool USBMouse::update(int16_t x, int16_t y, uint8_t button, int8_t z) {
+    switch (mouse_type) {
+        case REL_MOUSE:
+            while (x > 127) {
+                if (!mouseSend(127, 0, button, z)) return false;
+                x = x - 127;
+            }
+            while (x < -128) {
+                if (!mouseSend(-128, 0, button, z)) return false;
+                x = x + 128;
+            }
+            while (y > 127) {
+                if (!mouseSend(0, 127, button, z)) return false;
+                y = y - 127;
+            }
+            while (y < -128) {
+                if (!mouseSend(0, -128, button, z)) return false;
+                y = y + 128;
+            }
+            return mouseSend(x, y, button, z);
+        case ABS_MOUSE:
+            HID_REPORT report;
+
+            report.data[0] = x & 0xff;
+            report.data[1] = (x >> 8) & 0xff;
+            report.data[2] = y & 0xff;
+            report.data[3] = (y >> 8) & 0xff;
+            report.data[4] = -z;
+            report.data[5] = button & 0x07;
+
+            report.length = 6;
+
+            return send(&report);
+        default:
+            return false;
+    }
+}
+
+bool USBMouse::mouseSend(int8_t x, int8_t y, uint8_t buttons, int8_t z) {
+    HID_REPORT report;
+    report.data[0] = buttons & 0x07;
+    report.data[1] = x;
+    report.data[2] = y;
+    report.data[3] = -z; // >0 to scroll down, <0 to scroll up
+
+    report.length = 4;
+
+    return send(&report);
+}
+
+bool USBMouse::move(int16_t x, int16_t y) {
+    return update(x, y, button, 0);
+}
+
+bool USBMouse::scroll(int8_t z) {
+    return update(0, 0, button, z);
+}
+
+
+bool USBMouse::doubleClick() {
+    if (!click(MOUSE_LEFT))
+        return false;
+    wait(0.1);
+    return click(MOUSE_LEFT);
+}
+
+bool USBMouse::click(uint8_t button) {
+    if (!update(0, 0, button, 0))
+        return false;
+    wait(0.01);
+    return update(0, 0, 0, 0);
+}
+
+bool USBMouse::press(uint8_t button_) {
+    button = button_ & 0x07;
+    return update(0, 0, button, 0);
+}
+
+bool USBMouse::release(uint8_t button_) {
+    button = (button & (~button_)) & 0x07;
+    return update(0, 0, button, 0);
+}
+
+
+uint8_t * USBMouse::reportDesc() {
+
+    if (mouse_type == REL_MOUSE) {
+        static uint8_t reportDescriptor[] = {
+            USAGE_PAGE(1),      0x01,       // Genric Desktop
+            USAGE(1),           0x02,       // Mouse
+            COLLECTION(1),      0x01,       // Application
+            USAGE(1),           0x01,       // Pointer
+            COLLECTION(1),      0x00,       // Physical
+
+            REPORT_COUNT(1),    0x03,
+            REPORT_SIZE(1),     0x01,
+            USAGE_PAGE(1),      0x09,       // Buttons
+            USAGE_MINIMUM(1),       0x1,
+            USAGE_MAXIMUM(1),       0x3,
+            LOGICAL_MINIMUM(1),     0x00,
+            LOGICAL_MAXIMUM(1),     0x01,
+            INPUT(1),           0x02,
+            REPORT_COUNT(1),    0x01,
+            REPORT_SIZE(1),     0x05,
+            INPUT(1),           0x01,
+
+            REPORT_COUNT(1),    0x03,
+            REPORT_SIZE(1),     0x08,
+            USAGE_PAGE(1),      0x01,
+            USAGE(1),           0x30,       // X
+            USAGE(1),           0x31,       // Y
+            USAGE(1),           0x38,       // scroll
+            LOGICAL_MINIMUM(1),     0x81,
+            LOGICAL_MAXIMUM(1),     0x7f,
+            INPUT(1),           0x06,       // Relative data
+
+            END_COLLECTION(0),
+            END_COLLECTION(0),
+        };
+        reportLength = sizeof(reportDescriptor);
+        return reportDescriptor;
+    } else if (mouse_type == ABS_MOUSE) {
+        static uint8_t reportDescriptor[] = {
+
+            USAGE_PAGE(1), 0x01,           // Generic Desktop
+            USAGE(1), 0x02,                // Mouse
+            COLLECTION(1), 0x01,           // Application
+            USAGE(1), 0x01,                // Pointer
+            COLLECTION(1), 0x00,           // Physical
+
+            USAGE_PAGE(1), 0x01,            // Generic Desktop
+            USAGE(1), 0x30,                 // X
+            USAGE(1), 0x31,                 // Y
+            LOGICAL_MINIMUM(1), 0x00,       // 0
+            LOGICAL_MAXIMUM(2), 0xff, 0x7f, // 32767
+            REPORT_SIZE(1), 0x10,
+            REPORT_COUNT(1), 0x02,
+            INPUT(1), 0x02,                 // Data, Variable, Absolute
+
+            USAGE_PAGE(1), 0x01,            // Generic Desktop
+            USAGE(1), 0x38,                 // scroll
+            LOGICAL_MINIMUM(1), 0x81,       // -127
+            LOGICAL_MAXIMUM(1), 0x7f,       // 127
+            REPORT_SIZE(1), 0x08,
+            REPORT_COUNT(1), 0x01,
+            INPUT(1), 0x06,                 // Data, Variable, Relative
+
+            USAGE_PAGE(1), 0x09,            // Buttons
+            USAGE_MINIMUM(1), 0x01,
+            USAGE_MAXIMUM(1), 0x03,
+            LOGICAL_MINIMUM(1), 0x00,       // 0
+            LOGICAL_MAXIMUM(1), 0x01,       // 1
+            REPORT_COUNT(1), 0x03,
+            REPORT_SIZE(1), 0x01,
+            INPUT(1), 0x02,                 // Data, Variable, Absolute
+            REPORT_COUNT(1), 0x01,
+            REPORT_SIZE(1), 0x05,
+            INPUT(1), 0x01,                 // Constant
+
+            END_COLLECTION(0),
+            END_COLLECTION(0)
+        };
+        reportLength = sizeof(reportDescriptor);
+        return reportDescriptor;
+    }
+    return NULL;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHID/USBMouse.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,186 @@
+/* USBMouse.h */
+/* USB device example: relative mouse */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USBMOUSE_H
+#define USBMOUSE_H
+
+#include "USBHID.h"
+
+#define REPORT_ID_MOUSE   2
+
+/* Common usage */
+
+enum MOUSE_BUTTON
+{
+    MOUSE_LEFT = 1,
+    MOUSE_RIGHT = 2,
+    MOUSE_MIDDLE = 4,
+};
+
+/* X and Y limits */
+/* These values do not directly map to screen pixels */
+/* Zero may be interpreted as meaning 'no movement' */
+#define X_MIN_ABS    (1)        /*!< Minimum value on x-axis */  
+#define Y_MIN_ABS    (1)        /*!< Minimum value on y-axis */
+#define X_MAX_ABS    (0x7fff)   /*!< Maximum value on x-axis */
+#define Y_MAX_ABS    (0x7fff)   /*!< Maximum value on y-axis */
+
+#define X_MIN_REL    (-127)     /*!< The maximum value that we can move to the left on the x-axis */
+#define Y_MIN_REL    (-127)     /*!< The maximum value that we can move up on the y-axis */
+#define X_MAX_REL    (127)      /*!< The maximum value that we can move to the right on the x-axis */
+#define Y_MAX_REL    (127)      /*!< The maximum value that we can move down on the y-axis */
+
+enum MOUSE_TYPE
+{
+    ABS_MOUSE,
+    REL_MOUSE,
+};
+
+/**
+ *
+ * USBMouse example
+ * @code
+ * #include "mbed.h"
+ * #include "USBMouse.h"
+ *
+ * USBMouse mouse;
+ *
+ * int main(void)
+ * {
+ *   while (1)
+ *   {
+ *      mouse.move(20, 0);
+ *      wait(0.5);
+ *   }
+ * }
+ *
+ * @endcode
+ *
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "USBMouse.h"
+ * #include <math.h>
+ *
+ * USBMouse mouse(ABS_MOUSE);
+ *
+ * int main(void)
+ * {
+ *   uint16_t x_center = (X_MAX_ABS - X_MIN_ABS)/2;
+ *   uint16_t y_center = (Y_MAX_ABS - Y_MIN_ABS)/2;
+ *   uint16_t x_screen = 0;
+ *   uint16_t y_screen = 0;
+ *   
+ *   uint32_t x_origin = x_center;
+ *   uint32_t y_origin = y_center;
+ *   uint32_t radius = 5000;
+ *   uint32_t angle = 0;
+ *
+ *   while (1)
+ *   {
+ *       x_screen = x_origin + cos((double)angle*3.14/180.0)*radius;
+ *       y_screen = y_origin + sin((double)angle*3.14/180.0)*radius;
+ *       
+ *       mouse.move(x_screen, y_screen);
+ *       angle += 3;
+ *       wait(0.01);
+ *   }
+ * }
+ *
+ * @endcode
+ */
+class USBMouse: public USBHID
+{
+    public:
+        
+        /**
+        *   Constructor
+        *
+        * @param mouse_type Mouse type: ABS_MOUSE (absolute mouse) or REL_MOUSE (relative mouse) (default: REL_MOUSE)
+        * @param vendor_id Your vendor_id (default: 0x1234)
+        * @param product_id Your product_id (default: 0x0001)
+        * @param product_release Your preoduct_release (default: 0x0001)
+        *
+        */
+        USBMouse(MOUSE_TYPE mouse_type = REL_MOUSE, uint16_t vendor_id = 0x1234, uint16_t product_id = 0x0001, uint16_t product_release = 0x0001): 
+            USBHID(0, 0, vendor_id, product_id, product_release)
+            { 
+                button = 0;
+                this->mouse_type = mouse_type;
+            };
+        
+        /**
+        * Write a state of the mouse
+        *
+        * @param x x-axis position
+        * @param y y-axis position
+        * @param buttons buttons state (first bit represents MOUSE_LEFT, second bit MOUSE_RIGHT and third bit MOUSE_MIDDLE)
+        * @param z wheel state (>0 to scroll down, <0 to scroll up)
+        * @returns true if there is no error, false otherwise
+        */
+        bool update(int16_t x, int16_t y, uint8_t buttons, int8_t z);
+        
+        
+        /**
+        * Move the cursor to (x, y)
+        *
+        * @param x-axis position
+        * @param y-axis position
+        * @returns true if there is no error, false otherwise
+        */
+        bool move(int16_t x, int16_t y);
+        
+        /**
+        * Press one or several buttons
+        *
+        * @param button button state (ex: press(MOUSE_LEFT))
+        * @returns true if there is no error, false otherwise
+        */
+        bool press(uint8_t button);
+        
+        /**
+        * Release one or several buttons
+        *
+        * @param button button state (ex: release(MOUSE_LEFT))
+        * @returns true if there is no error, false otherwise
+        */
+        bool release(uint8_t button);
+        
+        /**
+        * Double click (MOUSE_LEFT)
+        *
+        * @returns true if there is no error, false otherwise
+        */
+        bool doubleClick();
+        
+        /**
+        * Click
+        *
+        * @param button state of the buttons ( ex: clic(MOUSE_LEFT))
+        * @returns true if there is no error, false otherwise
+        */
+        bool click(uint8_t button); 
+        
+        /**
+        * Scrolling
+        *
+        * @param z value of the wheel (>0 to go down, <0 to go up)
+        * @returns true if there is no error, false otherwise
+        */
+        bool scroll(int8_t z);
+        
+        /*
+        * To define the report descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
+        *
+        * @returns pointer to the report descriptor
+        */
+        virtual uint8_t * reportDesc();
+        
+    private:
+        MOUSE_TYPE mouse_type;
+        uint8_t button;
+        bool mouseSend(int8_t x, int8_t y, uint8_t buttons, int8_t z);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHID/USBMouseKeyboard.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,666 @@
+// Keyboard_RelMouse.c
+// USB device example: Keyboard and a relative mouse
+// Copyright (c) 2011 ARM Limited. All rights reserved.
+
+#include "stdint.h"
+#include "USBMouseKeyboard.h"
+
+typedef struct {
+    unsigned char usage;
+    unsigned char modifier;
+} KEYMAP;
+
+#ifdef US_KEYBOARD
+/* US keyboard (as HID standard) */
+#define KEYMAP_SIZE (145)
+const KEYMAP keymap[KEYMAP_SIZE] = {
+{0, 0},             /* NUL */
+{0, 0},             /* SOH */
+{0, 0},             /* STX */
+{0, 0},             /* ETX */
+{0, 0},             /* EOT */
+{0, 0},             /* ENQ */
+{0, 0},             /* ACK */
+{0, 0},             /* BEL */
+{0x2a, 0},          /* BS  */  /* Keyboard Delete (Backspace) */
+{0x2b, 0},          /* TAB */  /* Keyboard Tab */
+{0x28, 0},          /* LF  */  /* Keyboard Return (Enter) */
+{0, 0},             /* VT  */
+{0, 0},             /* FF  */
+{0, 0},             /* CR  */
+{0, 0},             /* SO  */
+{0, 0},             /* SI  */
+{0, 0},             /* DEL */
+{0, 0},             /* DC1 */
+{0, 0},             /* DC2 */
+{0, 0},             /* DC3 */
+{0, 0},             /* DC4 */
+{0, 0},             /* NAK */
+{0, 0},             /* SYN */
+{0, 0},             /* ETB */
+{0, 0},             /* CAN */
+{0, 0},             /* EM  */
+{0, 0},             /* SUB */
+{0, 0},             /* ESC */
+{0, 0},             /* FS  */
+{0, 0},             /* GS  */
+{0, 0},             /* RS  */
+{0, 0},             /* US  */
+{0x2c, 0},          /*   */
+{0x1e, KEY_SHIFT},      /* ! */
+{0x34, KEY_SHIFT},      /* " */
+{0x20, KEY_SHIFT},      /* # */
+{0x21, KEY_SHIFT},      /* $ */
+{0x22, KEY_SHIFT},      /* % */
+{0x24, KEY_SHIFT},      /* & */
+{0x34, 0},          /* ' */
+{0x26, KEY_SHIFT},      /* ( */
+{0x27, KEY_SHIFT},      /* ) */
+{0x25, KEY_SHIFT},      /* * */
+{0x2e, KEY_SHIFT},      /* + */
+{0x36, 0},          /* , */
+{0x2d, 0},          /* - */
+{0x37, 0},          /* . */
+{0x38, 0},          /* / */
+{0x27, 0},          /* 0 */
+{0x1e, 0},          /* 1 */
+{0x1f, 0},          /* 2 */
+{0x20, 0},          /* 3 */
+{0x21, 0},          /* 4 */
+{0x22, 0},          /* 5 */
+{0x23, 0},          /* 6 */
+{0x24, 0},          /* 7 */
+{0x25, 0},          /* 8 */
+{0x26, 0},          /* 9 */
+{0x33, KEY_SHIFT},      /* : */
+{0x33, 0},          /* ; */
+{0x36, KEY_SHIFT},      /* < */
+{0x2e, 0},          /* = */
+{0x37, KEY_SHIFT},      /* > */
+{0x38, KEY_SHIFT},      /* ? */
+{0x1f, KEY_SHIFT},      /* @ */
+{0x04, KEY_SHIFT},      /* A */
+{0x05, KEY_SHIFT},      /* B */
+{0x06, KEY_SHIFT},      /* C */
+{0x07, KEY_SHIFT},      /* D */
+{0x08, KEY_SHIFT},      /* E */
+{0x09, KEY_SHIFT},      /* F */
+{0x0a, KEY_SHIFT},      /* G */
+{0x0b, KEY_SHIFT},      /* H */
+{0x0c, KEY_SHIFT},      /* I */
+{0x0d, KEY_SHIFT},      /* J */
+{0x0e, KEY_SHIFT},      /* K */
+{0x0f, KEY_SHIFT},      /* L */
+{0x10, KEY_SHIFT},      /* M */
+{0x11, KEY_SHIFT},      /* N */
+{0x12, KEY_SHIFT},      /* O */
+{0x13, KEY_SHIFT},      /* P */
+{0x14, KEY_SHIFT},      /* Q */
+{0x15, KEY_SHIFT},      /* R */
+{0x16, KEY_SHIFT},      /* S */
+{0x17, KEY_SHIFT},      /* T */
+{0x18, KEY_SHIFT},      /* U */
+{0x19, KEY_SHIFT},      /* V */
+{0x1a, KEY_SHIFT},      /* W */
+{0x1b, KEY_SHIFT},      /* X */
+{0x1c, KEY_SHIFT},      /* Y */
+{0x1d, KEY_SHIFT},      /* Z */
+{0x2f, 0},          /* [ */
+{0x31, 0},          /* \ */
+{0x30, 0},          /* ] */
+{0x23, KEY_SHIFT},      /* ^ */
+{0x2d, KEY_SHIFT},      /* _ */
+{0x35, 0},          /* ` */
+{0x04, 0},          /* a */
+{0x05, 0},          /* b */
+{0x06, 0},          /* c */
+{0x07, 0},          /* d */
+{0x08, 0},          /* e */
+{0x09, 0},          /* f */
+{0x0a, 0},          /* g */
+{0x0b, 0},          /* h */
+{0x0c, 0},          /* i */
+{0x0d, 0},          /* j */
+{0x0e, 0},          /* k */
+{0x0f, 0},          /* l */
+{0x10, 0},          /* m */
+{0x11, 0},          /* n */
+{0x12, 0},          /* o */
+{0x13, 0},          /* p */
+{0x14, 0},          /* q */
+{0x15, 0},          /* r */
+{0x16, 0},          /* s */
+{0x17, 0},          /* t */
+{0x18, 0},          /* u */
+{0x19, 0},          /* v */
+{0x1a, 0},          /* w */
+{0x1b, 0},          /* x */
+{0x1c, 0},          /* y */
+{0x1d, 0},          /* z */
+{0x2f, KEY_SHIFT},      /* { */
+{0x31, KEY_SHIFT},      /* | */
+{0x30, KEY_SHIFT},      /* } */
+{0x35, KEY_SHIFT},      /* ~ */
+{0,0},              /* DEL */
+
+{0x3a, 0},          /* F1 */
+{0x3b, 0},          /* F2 */
+{0x3c, 0},          /* F3 */
+{0x3d, 0},          /* F4 */
+{0x3e, 0},          /* F5 */
+{0x3f, 0},          /* F6 */
+{0x40, 0},          /* F7 */
+{0x41, 0},          /* F8 */
+{0x42, 0},          /* F9 */
+{0x43, 0},          /* F10 */
+{0x44, 0},          /* F11 */
+{0x45, 0},          /* F12 */
+
+{0x46, 0},          /* PRINT_SCREEN */
+{0x49, 0},          /* INSERT */
+{0x4a, 0},          /* HOME */
+{0x4b, 0},          /* PAGE_UP */
+{0x4e, 0},          /* PAGE_DOWN */
+};
+
+#else
+/* UK keyboard */
+#define KEYMAP_SIZE (145)
+const KEYMAP keymap[KEYMAP_SIZE] = {
+{0, 0},             /* NUL */
+{0, 0},             /* SOH */
+{0, 0},             /* STX */
+{0, 0},             /* ETX */
+{0, 0},             /* EOT */
+{0, 0},             /* ENQ */
+{0, 0},             /* ACK */
+{0, 0},             /* BEL */
+{0x2a, 0},          /* BS  */  /* Keyboard Delete (Backspace) */
+{0x2b, 0},          /* TAB */  /* Keyboard Tab */
+{0x28, 0},          /* LF  */  /* Keyboard Return (Enter) */
+{0, 0},             /* VT  */
+{0, 0},             /* FF  */
+{0, 0},             /* CR  */
+{0, 0},             /* SO  */
+{0, 0},             /* SI  */
+{0, 0},             /* DEL */
+{0, 0},             /* DC1 */
+{0, 0},             /* DC2 */
+{0, 0},             /* DC3 */
+{0, 0},             /* DC4 */
+{0, 0},             /* NAK */
+{0, 0},             /* SYN */
+{0, 0},             /* ETB */
+{0, 0},             /* CAN */
+{0, 0},             /* EM  */
+{0, 0},             /* SUB */
+{0, 0},             /* ESC */
+{0, 0},             /* FS  */
+{0, 0},             /* GS  */
+{0, 0},             /* RS  */
+{0, 0},             /* US  */
+{0x2c, 0},          /*   */
+{0x1e, KEY_SHIFT},      /* ! */
+{0x1f, KEY_SHIFT},      /* " */
+{0x32, 0},          /* # */
+{0x21, KEY_SHIFT},      /* $ */
+{0x22, KEY_SHIFT},      /* % */
+{0x24, KEY_SHIFT},      /* & */
+{0x34, 0},          /* ' */
+{0x26, KEY_SHIFT},      /* ( */
+{0x27, KEY_SHIFT},      /* ) */
+{0x25, KEY_SHIFT},      /* * */
+{0x2e, KEY_SHIFT},      /* + */
+{0x36, 0},          /* , */
+{0x2d, 0},          /* - */
+{0x37, 0},          /* . */
+{0x38, 0},          /* / */
+{0x27, 0},          /* 0 */
+{0x1e, 0},          /* 1 */
+{0x1f, 0},          /* 2 */
+{0x20, 0},          /* 3 */
+{0x21, 0},          /* 4 */
+{0x22, 0},          /* 5 */
+{0x23, 0},          /* 6 */
+{0x24, 0},          /* 7 */
+{0x25, 0},          /* 8 */
+{0x26, 0},          /* 9 */
+{0x33, KEY_SHIFT},      /* : */
+{0x33, 0},          /* ; */
+{0x36, KEY_SHIFT},      /* < */
+{0x2e, 0},          /* = */
+{0x37, KEY_SHIFT},      /* > */
+{0x38, KEY_SHIFT},      /* ? */
+{0x34, KEY_SHIFT},      /* @ */
+{0x04, KEY_SHIFT},      /* A */
+{0x05, KEY_SHIFT},      /* B */
+{0x06, KEY_SHIFT},      /* C */
+{0x07, KEY_SHIFT},      /* D */
+{0x08, KEY_SHIFT},      /* E */
+{0x09, KEY_SHIFT},      /* F */
+{0x0a, KEY_SHIFT},      /* G */
+{0x0b, KEY_SHIFT},      /* H */
+{0x0c, KEY_SHIFT},      /* I */
+{0x0d, KEY_SHIFT},      /* J */
+{0x0e, KEY_SHIFT},      /* K */
+{0x0f, KEY_SHIFT},      /* L */
+{0x10, KEY_SHIFT},      /* M */
+{0x11, KEY_SHIFT},      /* N */
+{0x12, KEY_SHIFT},      /* O */
+{0x13, KEY_SHIFT},      /* P */
+{0x14, KEY_SHIFT},      /* Q */
+{0x15, KEY_SHIFT},      /* R */
+{0x16, KEY_SHIFT},      /* S */
+{0x17, KEY_SHIFT},      /* T */
+{0x18, KEY_SHIFT},      /* U */
+{0x19, KEY_SHIFT},      /* V */
+{0x1a, KEY_SHIFT},      /* W */
+{0x1b, KEY_SHIFT},      /* X */
+{0x1c, KEY_SHIFT},      /* Y */
+{0x1d, KEY_SHIFT},      /* Z */
+{0x2f, 0},          /* [ */
+{0x64, 0},          /* \ */
+{0x30, 0},          /* ] */
+{0x23, KEY_SHIFT},      /* ^ */
+{0x2d, KEY_SHIFT},      /* _ */
+{0x35, 0},          /* ` */
+{0x04, 0},          /* a */
+{0x05, 0},          /* b */
+{0x06, 0},          /* c */
+{0x07, 0},          /* d */
+{0x08, 0},          /* e */
+{0x09, 0},          /* f */
+{0x0a, 0},          /* g */
+{0x0b, 0},          /* h */
+{0x0c, 0},          /* i */
+{0x0d, 0},          /* j */
+{0x0e, 0},          /* k */
+{0x0f, 0},          /* l */
+{0x10, 0},          /* m */
+{0x11, 0},          /* n */
+{0x12, 0},          /* o */
+{0x13, 0},          /* p */
+{0x14, 0},          /* q */
+{0x15, 0},          /* r */
+{0x16, 0},          /* s */
+{0x17, 0},          /* t */
+{0x18, 0},          /* u */
+{0x19, 0},          /* v */
+{0x1a, 0},          /* w */
+{0x1b, 0},          /* x */
+{0x1c, 0},          /* y */
+{0x1d, 0},          /* z */
+{0x2f, KEY_SHIFT},      /* { */
+{0x64, KEY_SHIFT},      /* | */
+{0x30, KEY_SHIFT},      /* } */
+{0x32, KEY_SHIFT},      /* ~ */
+{0,0},             /* DEL */
+
+{0x3a, 0},          /* F1 */
+{0x3b, 0},          /* F2 */
+{0x3c, 0},          /* F3 */
+{0x3d, 0},          /* F4 */
+{0x3e, 0},          /* F5 */
+{0x3f, 0},          /* F6 */
+{0x40, 0},          /* F7 */
+{0x41, 0},          /* F8 */
+{0x42, 0},          /* F9 */
+{0x43, 0},          /* F10 */
+{0x44, 0},          /* F11 */
+{0x45, 0},          /* F12 */
+
+{0x46, 0},          /* PRINT_SCREEN */
+{0x49, 0},          /* INSERT */
+{0x4a, 0},          /* HOME */
+{0x4b, 0},          /* PAGE_UP */
+{0x4e, 0},          /* PAGE_DOWN */
+};
+#endif
+
+uint8_t * USBMouseKeyboard::reportDesc() {
+    if (mouse_type == REL_MOUSE) {
+        static uint8_t reportDescriptor[] = {
+                // Keyboard
+                USAGE_PAGE(1),      0x01,
+                USAGE(1),           0x06,
+                COLLECTION(1),      0x01,
+                REPORT_ID(1),       REPORT_ID_KEYBOARD,
+                USAGE_PAGE(1),      0x07,
+                USAGE_MINIMUM(1),       0xE0,
+                USAGE_MAXIMUM(1),       0xE7,
+                LOGICAL_MINIMUM(1),     0x00,
+                LOGICAL_MAXIMUM(1),     0x01,
+                REPORT_SIZE(1),     0x01,
+                REPORT_COUNT(1),    0x08,
+                INPUT(1),           0x02,
+                REPORT_COUNT(1),    0x01,
+                REPORT_SIZE(1),     0x08,
+                INPUT(1),           0x01,
+                REPORT_COUNT(1),    0x05,
+                REPORT_SIZE(1),     0x01,
+                USAGE_PAGE(1),      0x08,
+                USAGE_MINIMUM(1),       0x01,
+                USAGE_MAXIMUM(1),       0x05,
+                OUTPUT(1),          0x02,
+                REPORT_COUNT(1),    0x01,
+                REPORT_SIZE(1),     0x03,
+                OUTPUT(1),          0x01,
+                REPORT_COUNT(1),    0x06,
+                REPORT_SIZE(1),     0x08,
+                LOGICAL_MINIMUM(1),     0x00,
+                LOGICAL_MAXIMUM(2),     0xff, 0x00,
+                USAGE_PAGE(1),      0x07,
+                USAGE_MINIMUM(1),       0x00,
+                USAGE_MAXIMUM(2),       0xff, 0x00,
+                INPUT(1),           0x00,
+                END_COLLECTION(0),
+
+                // Mouse
+                USAGE_PAGE(1),      0x01,           // Generic Desktop
+                USAGE(1),           0x02,           // Mouse
+                COLLECTION(1),      0x01,           // Application
+                USAGE(1),           0x01,           // Pointer
+                COLLECTION(1),      0x00,           // Physical
+                REPORT_ID(1),       REPORT_ID_MOUSE,
+                REPORT_COUNT(1),    0x03,
+                REPORT_SIZE(1),     0x01,
+                USAGE_PAGE(1),      0x09,           // Buttons
+                USAGE_MINIMUM(1),       0x1,
+                USAGE_MAXIMUM(1),       0x3,
+                LOGICAL_MINIMUM(1),     0x00,
+                LOGICAL_MAXIMUM(1),     0x01,
+                INPUT(1),           0x02,
+                REPORT_COUNT(1),    0x01,
+                REPORT_SIZE(1),     0x05,
+                INPUT(1),           0x01,
+                REPORT_COUNT(1),    0x03,
+                REPORT_SIZE(1),     0x08,
+                USAGE_PAGE(1),      0x01,
+                USAGE(1),           0x30,           // X
+                USAGE(1),           0x31,           // Y
+                USAGE(1),           0x38,           // scroll
+                LOGICAL_MINIMUM(1),     0x81,
+                LOGICAL_MAXIMUM(1),     0x7f,
+                INPUT(1),           0x06,
+                END_COLLECTION(0),
+                END_COLLECTION(0),
+
+
+                // Media Control
+                USAGE_PAGE(1), 0x0C,
+                USAGE(1), 0x01,
+                COLLECTION(1), 0x01,
+                REPORT_ID(1), REPORT_ID_VOLUME,
+                USAGE_PAGE(1), 0x0C,
+                LOGICAL_MINIMUM(1), 0x00,
+                LOGICAL_MAXIMUM(1), 0x01,
+                REPORT_SIZE(1), 0x01,
+                REPORT_COUNT(1), 0x07,
+                USAGE(1), 0xB5,             // Next Track
+                USAGE(1), 0xB6,             // Previous Track
+                USAGE(1), 0xB7,             // Stop
+                USAGE(1), 0xCD,             // Play / Pause
+                USAGE(1), 0xE2,             // Mute
+                USAGE(1), 0xE9,             // Volume Up
+                USAGE(1), 0xEA,             // Volume Down
+                INPUT(1), 0x02,             // Input (Data, Variable, Absolute)
+                REPORT_COUNT(1), 0x01,
+                INPUT(1), 0x01,
+                END_COLLECTION(0),
+        };
+        reportLength = sizeof(reportDescriptor);
+        return reportDescriptor;
+    } else if (mouse_type == ABS_MOUSE) {
+        static uint8_t reportDescriptor[] = {
+
+                // Keyboard
+                USAGE_PAGE(1),      0x01,
+                USAGE(1),           0x06,
+                COLLECTION(1),      0x01,
+                REPORT_ID(1),       REPORT_ID_KEYBOARD,
+                USAGE_PAGE(1),      0x07,
+                USAGE_MINIMUM(1),       0xE0,
+                USAGE_MAXIMUM(1),       0xE7,
+                LOGICAL_MINIMUM(1),     0x00,
+                LOGICAL_MAXIMUM(1),     0x01,
+                REPORT_SIZE(1),     0x01,
+                REPORT_COUNT(1),    0x08,
+                INPUT(1),           0x02,
+                REPORT_COUNT(1),    0x01,
+                REPORT_SIZE(1),     0x08,
+                INPUT(1),           0x01,
+                REPORT_COUNT(1),    0x05,
+                REPORT_SIZE(1),     0x01,
+                USAGE_PAGE(1),      0x08,
+                USAGE_MINIMUM(1),       0x01,
+                USAGE_MAXIMUM(1),       0x05,
+                OUTPUT(1),          0x02,
+                REPORT_COUNT(1),    0x01,
+                REPORT_SIZE(1),     0x03,
+                OUTPUT(1),          0x01,
+                REPORT_COUNT(1),    0x06,
+                REPORT_SIZE(1),     0x08,
+                LOGICAL_MINIMUM(1),     0x00,
+                LOGICAL_MAXIMUM(2),     0xff, 0x00,
+                USAGE_PAGE(1),      0x07,
+                USAGE_MINIMUM(1),       0x00,
+                USAGE_MAXIMUM(2),       0xff, 0x00,
+                INPUT(1),           0x00,
+                END_COLLECTION(0),
+
+                // Mouse
+                USAGE_PAGE(1), 0x01,               // Generic Desktop
+                USAGE(1), 0x02,                    // Mouse
+                COLLECTION(1), 0x01,               // Application
+                USAGE(1), 0x01,                    // Pointer
+                COLLECTION(1), 0x00,               // Physical
+                REPORT_ID(1),       REPORT_ID_MOUSE,
+
+                USAGE_PAGE(1), 0x01,                // Generic Desktop
+                USAGE(1), 0x30,                     // X
+                USAGE(1), 0x31,                     // Y
+                LOGICAL_MINIMUM(1), 0x00,           // 0
+                LOGICAL_MAXIMUM(2), 0xff, 0x7f,     // 32767
+                REPORT_SIZE(1), 0x10,
+                REPORT_COUNT(1), 0x02,
+                INPUT(1), 0x02,                     // Data, Variable, Absolute
+
+                USAGE_PAGE(1), 0x01,                // Generic Desktop
+                USAGE(1), 0x38,                     // scroll
+                LOGICAL_MINIMUM(1), 0x81,           // -127
+                LOGICAL_MAXIMUM(1), 0x7f,           // 127
+                REPORT_SIZE(1), 0x08,
+                REPORT_COUNT(1), 0x01,
+                INPUT(1), 0x06,                     // Data, Variable, Relative
+
+                USAGE_PAGE(1), 0x09,                // Buttons
+                USAGE_MINIMUM(1), 0x01,
+                USAGE_MAXIMUM(1), 0x03,
+                LOGICAL_MINIMUM(1), 0x00,           // 0
+                LOGICAL_MAXIMUM(1), 0x01,           // 1
+                REPORT_COUNT(1), 0x03,
+                REPORT_SIZE(1), 0x01,
+                INPUT(1), 0x02,                     // Data, Variable, Absolute
+                REPORT_COUNT(1), 0x01,
+                REPORT_SIZE(1), 0x05,
+                INPUT(1), 0x01,                     // Constant
+
+                END_COLLECTION(0),
+                END_COLLECTION(0),
+
+                // Media Control
+                USAGE_PAGE(1), 0x0C,
+                USAGE(1), 0x01,
+                COLLECTION(1), 0x01,
+                REPORT_ID(1), REPORT_ID_VOLUME,
+                USAGE_PAGE(1), 0x0C,
+                LOGICAL_MINIMUM(1), 0x00,
+                LOGICAL_MAXIMUM(1), 0x01,
+                REPORT_SIZE(1), 0x01,
+                REPORT_COUNT(1), 0x07,
+                USAGE(1), 0xB5,             // Next Track
+                USAGE(1), 0xB6,             // Previous Track
+                USAGE(1), 0xB7,             // Stop
+                USAGE(1), 0xCD,             // Play / Pause
+                USAGE(1), 0xE2,             // Mute
+                USAGE(1), 0xE9,             // Volume Up
+                USAGE(1), 0xEA,             // Volume Down
+                INPUT(1), 0x02,             // Input (Data, Variable, Absolute)
+                REPORT_COUNT(1), 0x01,
+                INPUT(1), 0x01,
+                END_COLLECTION(0),
+        };
+        reportLength = sizeof(reportDescriptor);
+        return reportDescriptor;
+    }
+
+    return NULL;
+}
+
+bool USBMouseKeyboard::update(int16_t x, int16_t y, uint8_t button, int8_t z) {
+    switch (mouse_type) {
+    case REL_MOUSE:
+        while (x > 127) {
+            if (!mouseSend(127, 0, button, z)) return false;
+            x = x - 127;
+        }
+        while (x < -128) {
+            if (!mouseSend(-128, 0, button, z)) return false;
+            x = x + 128;
+        }
+        while (y > 127) {
+            if (!mouseSend(0, 127, button, z)) return false;
+            y = y - 127;
+        }
+        while (y < -128) {
+            if (!mouseSend(0, -128, button, z)) return false;
+            y = y + 128;
+        }
+        return mouseSend(x, y, button, z);
+    case ABS_MOUSE:
+        HID_REPORT report;
+
+        report.data[0] = REPORT_ID_MOUSE;
+        report.data[1] = x & 0xff;
+        report.data[2] = (x >> 8) & 0xff;
+        report.data[3] = y & 0xff;
+        report.data[4] = (y >> 8) & 0xff;
+        report.data[5] = -z;
+        report.data[6] = button & 0x07;
+
+        report.length = 7;
+
+        return send(&report);
+    default:
+        return false;
+    }
+}
+
+bool USBMouseKeyboard::mouseSend(int8_t x, int8_t y, uint8_t buttons, int8_t z) {
+    HID_REPORT report;
+    report.data[0] = REPORT_ID_MOUSE;
+    report.data[1] = buttons & 0x07;
+    report.data[2] = x;
+    report.data[3] = y;
+    report.data[4] = -z; // >0 to scroll down, <0 to scroll up
+
+    report.length = 5;
+
+    return send(&report);
+}
+
+bool USBMouseKeyboard::move(int16_t x, int16_t y) {
+    return update(x, y, button, 0);
+}
+
+bool USBMouseKeyboard::scroll(int8_t z) {
+    return update(0, 0, button, z);
+}
+
+bool USBMouseKeyboard::doubleClick() {
+    if (!click(MOUSE_LEFT))
+        return false;
+    wait(0.1);
+    return click(MOUSE_LEFT);
+}
+
+bool USBMouseKeyboard::click(uint8_t button) {
+    if (!update(0, 0, button, 0))
+        return false;
+    wait(0.01);
+    return update(0, 0, 0, 0);
+}
+
+bool USBMouseKeyboard::press(uint8_t button_) {
+    button = button_ & 0x07;
+    return update(0, 0, button, 0);
+}
+
+bool USBMouseKeyboard::release(uint8_t button_) {
+    button = (button & (~button_)) & 0x07;
+    return update(0, 0, button, 0);
+}
+
+int USBMouseKeyboard::_putc(int c) {
+    return keyCode(c, keymap[c].modifier);
+}
+
+bool USBMouseKeyboard::keyCode(uint8_t key, uint8_t modifier) {
+    // Send a simulated keyboard keypress. Returns true if successful.
+
+    HID_REPORT report;
+
+    report.data[0] = REPORT_ID_KEYBOARD;
+    report.data[1] = modifier;
+    report.data[2] = 0;
+    report.data[3] = keymap[key].usage;
+    report.data[4] = 0;
+    report.data[5] = 0;
+    report.data[6] = 0;
+    report.data[7] = 0;
+    report.data[8] = 0;
+
+    report.length = 9;
+
+    if (!send(&report)) {
+        return false;
+    }
+
+    report.data[1] = 0;
+    report.data[3] = 0;
+
+    if (!send(&report)) {
+        return false;
+    }
+
+    return true;
+
+}
+
+
+bool USBMouseKeyboard::mediaControl(MEDIA_KEY key) {
+    HID_REPORT report;
+
+    report.data[0] = REPORT_ID_VOLUME;
+    report.data[1] = (1 << key) & 0x7f;
+
+    report.length = 2;
+
+    send(&report);
+    
+    report.data[0] = REPORT_ID_VOLUME;
+    report.data[1] = 0;
+
+    report.length = 2;
+
+    return send(&report);
+}
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBHID/USBMouseKeyboard.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,185 @@
+/* USBMouseKeyboard.h */
+/* USB device example: Keyboard with a relative mouse */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USBMOUSEKEYBOARD_H
+#define USBMOUSEKEYBOARD_H
+
+#define REPORT_ID_KEYBOARD 1
+#define REPORT_ID_MOUSE 2
+#define REPORT_ID_VOLUME 3
+
+#include "USBMouse.h"
+#include "USBKeyboard.h"
+#include "Stream.h"
+#include "USBHID.h"
+
+/** 
+ * USBMouseKeyboard example
+ * @code
+ *
+ * #include "mbed.h"
+ * #include "USBMouseKeyboard.h"
+ *
+ * USBMouseKeyboard key_mouse;
+ *
+ * int main(void)
+ * {
+ *   while(1)
+ *   {
+ *       key_mouse.move(20, 0);
+ *       key_mouse.printf("Hello From MBED\r\n");
+ *       wait(1);
+ *   }
+ * }
+ * @endcode
+ *
+ *
+ * @code
+ *
+ * #include "mbed.h"
+ * #include "USBMouseKeyboard.h"
+ *
+ * USBMouseKeyboard key_mouse(ABS_MOUSE);
+ *
+ * int main(void)
+ * {
+ *   while(1)
+ *   {
+ *       key_mouse.move(X_MAX_ABS/2, Y_MAX_ABS/2);
+ *       key_mouse.printf("Hello from MBED\r\n");
+ *       wait(1);
+ *   }
+ * }
+ * @endcode
+ */
+class USBMouseKeyboard: public USBHID, public Stream
+{
+    public:
+    
+        /**
+        *   Constructor
+        *
+        * @param mouse_type Mouse type: ABS_MOUSE (absolute mouse) or REL_MOUSE (relative mouse) (default: REL_MOUSE)
+        * @param vendor_id Your vendor_id (default: 0x1234)
+        * @param product_id Your product_id (default: 0x0001)
+        * @param product_release Your preoduct_release (default: 0x0001)
+        *
+        */
+        USBMouseKeyboard(MOUSE_TYPE mouse_type = REL_MOUSE, uint16_t vendor_id = 0x0021, uint16_t product_id = 0x0011, uint16_t product_release = 0x0001): 
+            USBHID(0, 0, vendor_id, product_id, product_release)
+            {
+                button = 0;
+                this->mouse_type = mouse_type;
+            };
+        
+        
+        /**
+        * Write a state of the mouse
+        *
+        * @param x x-axis position
+        * @param y y-axis position
+        * @param buttons buttons state (first bit represents MOUSE_LEFT, second bit MOUSE_RIGHT and third bit MOUSE_MIDDLE)
+        * @param z wheel state (>0 to scroll down, <0 to scroll up)
+        * @returns true if there is no error, false otherwise
+        */
+        bool update(int16_t x, int16_t y, uint8_t buttons, int8_t z);
+        
+        
+        /**
+        * Move the cursor to (x, y)
+        *
+        * @param x x-axis position
+        * @param y y-axis position
+        * @returns true if there is no error, false otherwise
+        */
+        bool move(int16_t x, int16_t y);
+        
+        /**
+        * Press one or several buttons
+        *
+        * @param button button state (ex: press(MOUSE_LEFT))
+        * @returns true if there is no error, false otherwise
+        */
+        bool press(uint8_t button);
+        
+        /**
+        * Release one or several buttons
+        *
+        * @param button button state (ex: release(MOUSE_LEFT))
+        * @returns true if there is no error, false otherwise
+        */
+        bool release(uint8_t button);
+        
+        /**
+        * Double click (MOUSE_LEFT)
+        *
+        * @returns true if there is no error, false otherwise
+        */
+        bool doubleClick();
+        
+        /**
+        * Click
+        *
+        * @param button state of the buttons ( ex: clic(MOUSE_LEFT))
+        * @returns true if there is no error, false otherwise
+        */
+        bool click(uint8_t button); 
+        
+        /**
+        * Scrolling
+        *
+        * @param z value of the wheel (>0 to go down, <0 to go up)
+        * @returns true if there is no error, false otherwise
+        */
+        bool scroll(int8_t z);
+
+        /**
+        * To send a character defined by a modifier(CTRL, SHIFT, ALT) and the key 
+        *
+        * @code
+        * //To send CTRL + s (save)
+        *  keyboard.keyCode('s', KEY_CTRL);
+        * @endcode
+        *
+        * @param modifier bit 0: KEY_CTRL, bit 1: KEY_SHIFT, bit 2: KEY_ALT (default: 0)
+        * @param key character to send
+        * @returns true if there is no error, false otherwise
+        */
+        bool keyCode(uint8_t key, uint8_t modifier = 0);
+        
+        /**
+        * Send a character
+        *
+        * @param c character to be sent
+        * @returns true if there is no error, false otherwise
+        */
+        virtual int _putc(int c);
+        
+        /**
+        * Control media keys
+        *
+        * @param key media key pressed (KEY_NEXT_TRACK, KEY_PREVIOUS_TRACK, KEY_STOP, KEY_PLAY_PAUSE, KEY_MUTE, KEY_VOLUME_UP, KEY_VOLUME_DOWN)
+        * @returns true if there is no error, false otherwise
+        */
+        bool mediaControl(MEDIA_KEY key);
+        
+        /*
+        * To define the report descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
+        *
+        * @returns pointer to the report descriptor
+        */
+        virtual uint8_t * reportDesc();
+        
+        
+    private:
+        bool mouseWrite(int8_t x, int8_t y, uint8_t buttons, int8_t z);
+        MOUSE_TYPE mouse_type;
+        uint8_t button;
+        bool mouseSend(int8_t x, int8_t y, uint8_t buttons, int8_t z);
+        
+        //dummy otherwise it doesn,t compile (we must define all methods of an abstract class)
+        virtual int _getc() { return -1;}
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBMIDI/MIDIMessage.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,254 @@
+/* @license The MIT License
+ * Copyright (c) 2011 mux, simon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *  
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MIDIMESSAGE_H
+#define MIDIMESSAGE_H
+
+#include "mbed.h"
+
+// MIDI Message Format
+// 
+// [ msg(4) | channel(4) ] [ 0 | n(7) ] [ 0 | m(7) ]
+//
+// MIDI Data Messages (Channel Specific)
+//
+// Message               msg n          m
+// ---------------------------------------------
+// Note Off              0x8 Key        Velocity
+// Note On               0x9 Key        Velocity
+// Polyphonic Aftertouch 0xA Key        Pressure
+// Control Change        0xB Controller Value
+// Program Change        0xC Program    -
+// Channel Aftertouch    0xD Pressure   -
+// Pitch Wheel           0xE LSB        MSB
+
+#define CABLE_NUM (0<<4)
+
+/** A MIDI message container */
+class MIDIMessage {
+public:
+    MIDIMessage() {}
+    
+    MIDIMessage(uint8_t *buf) {
+        *((uint32_t *)data) = *((uint32_t *)buf);
+    }
+    
+    // create messages
+    
+    /** Create a NoteOff message 
+     * @param key Key ID
+     * @param velocity Key velocity (0-127, default = 127)
+     * @param channel Key channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */
+    static MIDIMessage NoteOff(int key, int velocity = 127, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x08;
+        msg.data[1] = 0x80 | (channel & 0x0F);
+        msg.data[2] = key & 0x7F;
+        msg.data[3] = velocity & 0x7F; 
+        return msg;
+    }
+    
+    /** Create a NoteOn message 
+     * @param key Key ID
+     * @param velocity Key velocity (0-127, default = 127)
+     * @param channel Key channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */
+    static MIDIMessage NoteOn(int key, int velocity = 127, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x09;
+        msg.data[1] = 0x90 | (channel & 0x0F);
+        msg.data[2] = key & 0x7F;
+        msg.data[3] = velocity & 0x7F;                 
+        return msg;
+    }
+    
+    /** Create a PolyPhonic Aftertouch message 
+     * @param key Key ID
+     * @param pressure Aftertouch pressure (0-127)
+     * @param channel Key channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage PolyphonicAftertouch(int key, int pressure, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x0A;
+        msg.data[1] = 0xA0 | (channel & 0x0F);
+        msg.data[2] = key & 0x7F;
+        msg.data[3] = pressure & 0x7F;         
+        return msg;
+    }
+    
+    /** Create a Control Change message 
+     * @param control Controller ID
+     * @param value Controller value (0-127)
+     * @param channel Controller channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */
+    static MIDIMessage ControlChange(int control, int value, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x0B;
+        msg.data[1] = 0xB0 | (channel & 0x0F);
+        msg.data[2] = control & 0x7F;
+        msg.data[3] = value & 0x7F;         
+        return msg;
+    }
+    
+    /** Create a Program Change message 
+     * @param program Program ID
+     * @param channel Channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage ProgramChange(int program, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x0C;
+        msg.data[1] = 0xC0 | (channel & 0x0F);
+        msg.data[2] = program & 0x7F;
+        msg.data[3] = 0x00;         
+        return msg;
+    }
+    
+    /** Create a Channel Aftertouch message 
+     * @param pressure Pressure 
+     * @param channel Key channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage ChannelAftertouch(int pressure, int channel = 0) {
+        MIDIMessage msg;
+        msg.data[0] = CABLE_NUM | 0x0D;
+        msg.data[1] = 0xD0 | (channel & 0x0F);
+        msg.data[2] = pressure & 0x7F;
+        msg.data[3] = 0x00;         
+        return msg;
+    }
+    
+    /** Create a Pitch Wheel message 
+     * @param pitch Pitch (-8192 - 8191, default = 0)
+     * @param channel Channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage PitchWheel(int pitch = 0, int channel = 0) {
+        MIDIMessage msg;
+        int p = pitch + 8192;    // 0 - 16383, 8192 is center
+        msg.data[0] = CABLE_NUM | 0x0E;
+        msg.data[1] = 0xE0 | (channel & 0x0F);
+        msg.data[2] = p & 0x7F;
+        msg.data[3] = (p >> 7) & 0x7F;                 
+        return msg;
+    }
+    
+    /** Create an All Notes Off message 
+     * @param channel Channel (0-15, default 0)
+     * @returns A MIDIMessage
+     */    
+    static MIDIMessage AllNotesOff(int channel = 0) {
+        return ControlChange(123, 0, channel);
+    }
+    
+    // decode messages
+    
+    /** MIDI Message Types */
+    enum MIDIMessageType {
+        ErrorType,
+        NoteOffType,
+        NoteOnType,
+        PolyphonicAftertouchType,
+        ControlChangeType,
+        ProgramChangeType,
+        ChannelAftertouchType,
+        PitchWheelType,
+        AllNotesOffType
+    };
+    
+    /** Read the message type
+     * @returns MIDIMessageType
+     */    
+    MIDIMessageType type() {
+        switch((data[1] >> 4) & 0xF) {
+            case 0x8: return NoteOffType;
+            case 0x9: return NoteOnType;
+            case 0xA: return PolyphonicAftertouchType;
+            case 0xB: 
+                if(controller() < 120) { // standard controllers
+                    return ControlChangeType;
+                } else if(controller() == 123) {
+                    return AllNotesOffType;
+                } else {
+                    return ErrorType; // unsupported atm
+                }
+            case 0xC: return ProgramChangeType;
+            case 0xD: return ChannelAftertouchType;
+            case 0xE: return PitchWheelType;
+            default: return ErrorType;
+        }
+    }
+
+    /** Read the channel number */    
+    int channel() {
+        return (data[1] & 0x0F);
+    }
+    
+    /** Read the key ID */    
+    int key() {
+        return (data[2] & 0x7F);        
+    }
+        
+    /** Read the velocity */    
+    int velocity() {
+        return (data[3] & 0x7F);        
+    }
+
+    /** Read the controller value */    
+    int value() {
+        return (data[3] & 0x7F);        
+    }
+    
+    /** Read the aftertouch pressure */        
+    int pressure() {
+        if(type() == PolyphonicAftertouchType) {
+            return (data[3] & 0x7F);        
+        } else {
+            return (data[2] & 0x7F);        
+        }
+    }
+
+    /** Read the controller number */    
+    int controller() {
+        return (data[2] & 0x7F);        
+    }
+
+    /** Read the program number */    
+    int program() {
+        return (data[2] & 0x7F);        
+    }
+    
+    /** Read the pitch value */        
+    int pitch() {
+        int p = ((data[3] & 0x7F) << 7) | (data[2] & 0x7F);
+        return p - 8192; // 0 - 16383, 8192 is center
+    }
+    
+    uint8_t data[4];
+};    
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBMIDI/USBMIDI.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,107 @@
+// USB_MIDI.cpp
+// MIDI edvice example
+// Copyright (c) 2011 ARM Limited. All rights reserved.
+
+#include "stdint.h"
+#include "USBMIDI.h"
+#include "USBBusInterface.h"
+
+
+USBMIDI::USBMIDI(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) {
+    midi_evt = NULL;
+}
+
+void USBMIDI::write(MIDIMessage m) {
+    USBDevice::write(EPBULK_IN, m.data, 4, MAX_PACKET_SIZE_EPBULK);
+}
+
+
+void USBMIDI::attach(void (*fptr)(MIDIMessage)) {
+    midi_evt = fptr;
+}
+
+
+bool USBMIDI::EPBULK_OUT_callback() {
+    uint8_t buf[64];
+    uint16_t len;
+    read(EPBULK_OUT, buf, &len, 64);
+
+    if (midi_evt != NULL) {
+        for (int i=0; i<len; i+=4) {
+            midi_evt(MIDIMessage(buf+i));
+        }
+    }
+
+    // We reactivate the endpoint to receive next characters
+    readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+    return true;
+}
+
+
+
+bool USBMIDI::USBCallback_setConfiguration(uint8_t configuration) {
+    // Called in ISR context
+    // Set configuration. Return false if the
+    // configuration is not supported.
+    if (configuration != DEFAULT_CONFIGURATION) {
+        return false;
+    }
+
+    // Configure endpoints > 0
+    addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
+    addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+
+    // We activate the endpoint to be able to receive data
+    readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+    return true;
+}
+
+
+uint8_t * USBMIDI::stringIinterfaceDesc() {
+    static uint8_t stringIinterfaceDescriptor[] = {
+        0x0c,                           //bLength
+        STRING_DESCRIPTOR,              //bDescriptorType 0x03
+        'A',0,'u',0,'d',0,'i',0,'o',0   //bString iInterface - Audio
+    };
+    return stringIinterfaceDescriptor;
+}
+
+uint8_t * USBMIDI::stringIproductDesc() {
+    static uint8_t stringIproductDescriptor[] = {
+        0x16,                                                       //bLength
+        STRING_DESCRIPTOR,                                          //bDescriptorType 0x03
+        'M',0,'b',0,'e',0,'d',0,' ',0,'A',0,'u',0,'d',0,'i',0,'o',0 //bString iProduct - Mbed Audio
+    };
+    return stringIproductDescriptor;
+}
+
+
+uint8_t * USBMIDI::configurationDesc() {
+    static uint8_t configDescriptor[] = {
+        // configuration descriptor
+        0x09, 0x02, 0x65, 0x00, 0x02, 0x01, 0x00, 0xc0, 0x50,
+
+        // The Audio Interface Collection
+        0x09, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, // Standard AC Interface Descriptor
+        0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, // Class-specific AC Interface Descriptor
+        0x09, 0x04, 0x01, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, // MIDIStreaming Interface Descriptors
+        0x07, 0x24, 0x01, 0x00, 0x01, 0x41, 0x00,             // Class-Specific MS Interface Header Descriptor
+
+        // MIDI IN JACKS
+        0x06, 0x24, 0x02, 0x01, 0x01, 0x00,
+        0x06, 0x24, 0x02, 0x02, 0x02, 0x00,
+
+        // MIDI OUT JACKS
+        0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00,
+        0x09, 0x24, 0x03, 0x02, 0x06, 0x01, 0x01, 0x01, 0x00,
+
+        // OUT endpoint descriptor
+        0x09, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
+        0x05, 0x25, 0x01, 0x01, 0x01,
+
+        // IN endpoint descriptor
+        0x09, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
+        0x05, 0x25, 0x01, 0x01, 0x03,
+    };
+    return configDescriptor;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice/USBMIDI/USBMIDI.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,97 @@
+/* USB_MIDI.h */
+/* MIDI device example */
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+
+#ifndef USBMIDI_H
+#define USBMIDI_H
+
+/* These headers are included for child class. */
+#include "USBEndpoints.h"
+#include "USBDescriptor.h"
+#include "USBDevice_Types.h"
+
+#include "USBDevice.h"
+#include "MIDIMessage.h"
+
+#define DEFAULT_CONFIGURATION (1)
+
+/** 
+* USBMIDI example
+*
+* @code
+* #include "mbed.h"
+* #include "USBMIDI.h"
+*
+* USBMIDI midi;
+*
+* int main() {            
+*    while (1) {    
+*        for(int i=48; i<83; i++) {     // send some messages!
+*            midi.write(MIDIMessage::NoteOn(i));
+*            wait(0.25);
+*            midi.write(MIDIMessage::NoteOff(i));
+*            wait(0.5);
+*        }
+*    }
+* }
+* @endcode
+*/
+class USBMIDI: public USBDevice {
+public:
+
+    /**
+    * Constructor
+    *
+    * @param vendor_id Your vendor_id
+    * @param product_id Your product_id
+    * @param product_release Your preoduct_release
+    */
+    USBMIDI(uint16_t vendor_id = 0x0700, uint16_t product_id = 0x0101, uint16_t product_release = 0x0001);
+    
+    /*
+    * Get string product descriptor
+    *
+    * @returns pointer to the string product descriptor
+    */
+    virtual uint8_t * stringIproductDesc();
+    
+    /*
+    * Get string interface descriptor
+    *
+    * @returns pointer to the string interface descriptor
+    */
+    virtual uint8_t * stringIinterfaceDesc();
+    
+    /*
+    * Get configuration descriptor
+    *
+    * @returns pointer to the configuration descriptor
+    */
+    virtual uint8_t * configurationDesc();
+    
+    /**
+     * Send a MIDIMessage
+     *
+     * @param m The MIDIMessage to send
+     */    
+    void write(MIDIMessage m);
+
+    /**
+     * Attach a callback for when a MIDIEvent is received
+     *
+     * @param fptr function pointer
+     */
+    void attach(void (*fptr)(MIDIMessage));
+    
+    virtual bool USBCallback_setConfiguration(uint8_t configuration);
+    
+protected:
+    virtual bool EPBULK_OUT_callback();
+
+private:
+    void (*midi_evt)(MIDIMessage);
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSC.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,156 @@
+// USB_MIDI.cpp
+// MIDI edvice example
+// Copyright (c) 2011 ARM Limited. All rights reserved.
+
+//#define DEBUG
+#include "dbg.h"
+#include "stdint.h"
+#include "USBMSC.h"
+#include "USBBusInterface.h"
+#include "USBDevice.h"
+#include "USBDevice_Types.h"
+
+void USBMSC::setTransferData (uint8_t *buf, int len) {
+    CONTROL_TRANSFER *transfer = getTransferPtr();
+    transfer->remaining = len;
+    transfer->ptr = buf;
+    transfer->direction = DEVICE_TO_HOST;
+}
+
+void USBMSC::attach(void (*fptr)(uint8_t)) {
+    msc_evt = fptr;
+}
+
+USBMSC::USBMSC(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) {
+    msc_evt = NULL;
+}
+
+bool USBMSC::EPBULK_OUT_callback() {
+
+    if (msc_evt && ! getEndpointStallState(EPBULK_OUT)) {
+        msc_evt(EPBULK_OUT);
+    }
+
+    // We reactivate the endpoint to receive next characters
+    readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+    DBG("EPBULK_OUT_callback\r\n");
+    return true;
+}
+
+bool USBMSC::EPBULK_IN_callback() {
+    DBG("EPBULK_IN_callback\r\n");
+
+    if (msc_evt && ! getEndpointStallState(EPBULK_IN)) {
+        msc_evt(EPBULK_IN);
+    }
+
+    return false;
+}
+
+bool USBMSC::USBCallback_request () {
+    bool success = false;
+    CONTROL_TRANSFER *transfer = getTransferPtr();
+    
+    DBG("USBCallback_request: type %x, request %x\r\n", transfer->setup.bmRequestType.Type, transfer->setup.bRequest);
+    /* Process standard requests */
+    if ((transfer->setup.bmRequestType.Type == STANDARD_TYPE))
+    {
+        switch (transfer->setup.bRequest)
+        {
+            default:
+                break;
+        }
+    }
+
+    if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
+    {
+        switch (transfer->setup.bRequest)
+        {
+            case 0xFE: // MSC get max LUN
+                static uint8_t dummy[] = {0}; 
+                transfer->remaining = 1;
+                transfer->ptr = dummy;
+                transfer->direction = DEVICE_TO_HOST;
+                success = true;
+                break;
+            case 0xFF: // MSC reset
+                if (transfer->setup.wLength == 0) {
+                    if (msc_evt) {
+                        msc_evt(0xFF);
+                    }
+                    success = true;
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    return success;
+}
+
+bool USBMSC::USBCallback_setConfiguration(uint8_t configuration) {
+    DBG("USBCallback_setConfiguration: config %x\r\n", configuration);
+    // Called in ISR context
+    // Set configuration. Return false if the
+    // configuration is not supported.
+    if (configuration != DEFAULT_CONFIGURATION) {
+        return false;
+    }
+
+    addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
+
+    // enable bulk-in interrupts on NAKs
+    // these are required to get the BOT protocol going again after a STALL
+    NakIntEnable(EPBULK_IN);
+
+    // Configure endpoints > 0
+    addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
+    addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+
+    // We activate the endpoint to be able to receive data
+    readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
+
+    return true;
+}
+
+uint8_t * USBMSC::configurationDesc() {
+    static uint8_t configDescriptor[] = {
+        // configuration descriptor
+        0x09, 0x02, 32, 0x00, 0x01, 0x01, 0x00, 0xC0, 0x32,
+
+        // MSC
+        // control class interface
+        0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, 0x00,
+        // EP OUT
+        0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
+        // EP IN
+        0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00,
+    };
+    DBG("configurationDesc %d\r\n", sizeof(configDescriptor));
+    return configDescriptor;
+}
+
+uint8_t * USBMSC::deviceDesc() {
+    static uint8_t deviceDescriptor[] = {
+        DEVICE_DESCRIPTOR_LENGTH,       /* bLength */
+        DEVICE_DESCRIPTOR,              /* bDescriptorType */
+        LSB(USB_VERSION_2_0),           /* bcdUSB (LSB) */
+        MSB(USB_VERSION_2_0),           /* bcdUSB (MSB) */
+        0x00,                           /* bDeviceClass */
+        0x00,                           /* bDeviceSubClass */
+        0x00,                           /* bDeviceprotocol */
+        MAX_PACKET_SIZE_EP0,            /* bMaxPacketSize0 */
+        LSB(VENDOR_ID),                 /* idVendor (LSB) */
+        MSB(VENDOR_ID),                 /* idVendor (MSB) */
+        LSB(PRODUCT_ID),                /* idProduct (LSB) */
+        MSB(PRODUCT_ID),                /* idProduct (MSB) */
+        LSB(PRODUCT_RELEASE),           /* bcdDevice (LSB) */
+        MSB(PRODUCT_RELEASE),           /* bcdDevice (MSB) */
+        STRING_OFFSET_IMANUFACTURER,    /* iManufacturer */
+        STRING_OFFSET_IPRODUCT,         /* iProduct */
+        STRING_OFFSET_ISERIAL,          /* iSerialNumber */
+        0x01                            /* bNumConfigurations */
+    };
+    return deviceDescriptor;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBMSC.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,51 @@
+
+#ifndef USBMSC_H
+#define USBMSC_H
+
+/* These headers are included for child class. */
+#include "USBEndpoints.h"
+#include "USBDescriptor.h"
+#include "USBDevice_Types.h"
+
+#include "USBDevice.h"
+
+#define DEFAULT_CONFIGURATION (1)
+
+class USBMSC: public USBDevice {
+public:
+
+    /**
+    * Constructor
+    *
+    * @param vendor_id Your vendor_id
+    * @param product_id Your product_id
+    * @param product_release Your preoduct_release
+    */
+    USBMSC(uint16_t vendor_id = 0x1FC9, uint16_t product_id = 0x1002, uint16_t product_release = 0x0100);
+    
+    /*
+    * Get configuration descriptor
+    *
+    * @returns pointer to the configuration descriptor
+    */
+    virtual uint8_t * configurationDesc();
+    virtual uint8_t * deviceDesc();
+    
+    virtual bool USBCallback_setConfiguration(uint8_t configuration);
+    
+    virtual bool USBCallback_request ();
+
+    void attach(void (*fptr)(uint8_t));
+
+    void setTransferData (uint8_t *buf, int len);
+
+protected:
+    virtual bool EPBULK_OUT_callback();
+    virtual bool EPBULK_IN_callback();
+
+private:
+    void (*msc_evt)(uint8_t);
+
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/blockdev.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,38 @@
+/*
+    LPCUSB, an USB device driver for LPC microcontrollers    
+    Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. The name of the author may not be used to endorse or promote products
+       derived from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mbed.h"
+
+
+int BlockDevInit(void);
+
+int BlockDevWrite(uint32_t dwAddress, uint8_t* pbBuf);
+int BlockDevRead(uint32_t dwAddress, uint8_t* pbBuf);
+
+//int BlockDevGetSize(U32 *pdwDriveSize);
+uint32_t BlockDevGetSize(void);
+int BlockDevGetStatus(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/blockdev_sd.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,75 @@
+/*****************************************************************************\
+*              efs - General purpose Embedded Filesystem library              *
+*          --------------------- -----------------------------------          *
+*                                                                             *
+* Filename : sd.c                                                             *
+* Revision : Initial developement                                             *
+* Description : This file contains the functions needed to use efs for        *
+*               accessing files on an SD-card.                                *
+*                                                                             *
+* This library is free software; you can redistribute it and/or               *
+* modify it under the terms of the GNU Lesser General Public                  *
+* License as published by the Free Software Foundation; either                *
+* version 2.1 of the License, or (at your option) any later version.          *
+*                                                                             *
+* This library 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           *
+* Lesser General Public License for more details.                             *
+*                                                                             *
+*                                                    (c)2005 Michael De Nil   *
+*                                                    (c)2005 Lennart Yseboodt *
+\*****************************************************************************/
+
+/*
+    2006, Bertrik Sikken, modified for LPCUSB
+*/
+/*
+ *  Modified for mbed NXP LPC1768 & LPCXpresso board
+ *
+ *  NOT USE efs library
+ *  USE FatFs interface routine
+ *
+ *  original    LPC214x USB stack beta by bertrik
+ *              target-20070727.tar.gr (119.5KB)
+ *              http://sourceforge.net/projects/lpcusb/
+ *  By Kenji Arai / JH1PJL on September 25th, 2010
+ *      October 3rd, 2010
+ */
+
+//#define DEBUG
+#include "dbg.h"
+#include "mbed.h"
+
+#include "blockdev.h"
+#include "SDFileSystem.h"
+
+
+extern SDFileSystem sd;
+
+// Get Device media size
+uint32_t BlockDevGetSize()
+{
+    DBG("BlockDevGetSize\r\n");
+    return sd.disk_sectors() * 512;
+}
+
+// Initialize
+int BlockDevInit(void)
+{
+    DBG("BlockDevInit\r\n");
+//    return sd.disk_initialize(0);    // Drive # = 0
+    return 0;
+}
+
+int BlockDevWrite(uint32_t dwAddress, uint8_t * pbBuf)
+{
+    //( drive #=0, data buffer to write the data, sector's address, Number of Blocks=1 )
+    return sd.disk_write((char*)pbBuf, dwAddress);    // return=0 -> success
+}
+
+int BlockDevRead(uint32_t dwAddress, uint8_t * pbBuf)
+{
+    //( drive #=0, data buffer to read the data, sector's address, Number of Blocks=1 )
+    return sd.disk_read((char*)pbBuf, dwAddress);    // return=0 -> success
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbg.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,7 @@
+//#define DEBUG
+
+#ifdef DEBUG 
+#define DBG(...) printf("dbg:" __VA_ARGS__) 
+#else 
+#define DBG(...) 
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,75 @@
+#include "mbed.h"
+#include "dbg.h"
+#include "USBMSC.h"
+
+#include "msc_bot.h"
+#include "SDFileSystem.h"
+#include "wavplayer.h"
+#include <new>
+
+Serial pc(USBTX, USBRX);
+DigitalOut myled(LED1);
+SDFileSystem sd(p5, p6, p7, p24, "sd");
+DigitalIn button(p21);
+USBMSC usbdev;
+
+DigitalOut volCLK(p22);
+//USBMSC usbdev(0xFFFF, 0x0003, 0x0100);
+
+extern "C"
+void HardFault_Handler() {
+    printf("Hard Fault!\n");
+    exit(-1);
+}
+
+void no_memory () {
+    printf("panic: can't allocate to memory!\r\n");
+    exit(-1);
+}
+
+void msc_evt (uint8_t endpoint) {
+    switch (endpoint) {
+    case EPBULK_OUT:
+        MSCBotBulkOut();
+        break;
+    case EPBULK_IN:
+        MSCBotBulkIn();
+        break;
+    case 0xFF:
+        MSCBotReset();
+        break;
+    }
+}
+
+int main() {
+    button.mode(PullUp);
+    WavPlayer myWavPlayer;
+
+    set_new_handler(no_memory); // new handler function
+    FILE *fp = fopen("/sd/settings.txt", "r");
+	char array[17];
+	if (fp) {
+        while(fgets(array, 17, fp)){
+        	pc.printf("file: %s\r\n",array);
+		}
+        fclose(fp);
+    }
+    if (fp == NULL) {
+        pc.printf("Could not open file for write\n");
+		fclose(fp);
+    }
+
+    MSCBotReset();
+    usbdev.attach(&msc_evt);
+    
+   
+    while(1) {
+        if(button == 0){ 
+            myWavPlayer.play_wave(array); //  8 bit sample size
+        }   
+        myled = 1;
+        wait(0.5);
+        myled = 0;
+        wait(0.5);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/msc_bot.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,400 @@
+/*
+    LPCUSB, an USB device driver for LPC microcontrollers    
+    Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. The name of the author may not be used to endorse or promote products
+       derived from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**    @file
+
+    Bulk-only-transfer layer for mass storage.
+    
+    This layers sits between the generic USB layers and the SCSI layer
+    and performs data transfer according to the BOT protocol.
+*/
+
+//#define DEBUG
+#include "dbg.h"
+#include "mbed.h"
+#include <string.h>
+
+#include "msc_bot.h"
+#include "msc_scsi.h"
+#include "USBMSC.h"
+
+extern USBMSC usbdev;
+
+/** Command block wrapper structure */
+struct TCBW {
+    uint32_t        dwCBWSignature;
+    uint32_t        dwCBWTag;
+    uint32_t        dwCBWDataTransferLength;
+    uint8_t        bmCBWFlags;
+    uint8_t        bCBWLun;
+    uint8_t        bCBWCBLength;
+    uint8_t        CBWCB[16];
+    uint8_t         dummy[MAX_PACKET_SIZE_EPBULK - 31];
+} __attribute__((packed));
+
+/** Command status wrapper structure */
+struct TCSW {
+    uint32_t        dwCSWSignature;
+    uint32_t        dwCSWTag;
+    uint32_t        dwCSWDataResidue;
+    uint8_t        bmCSWStatus;
+    uint8_t         dummy[MAX_PACKET_SIZE_EPBULK - 13];
+} __attribute__((packed));
+
+/** States of BOT state machine */
+typedef enum {
+    eCBW,
+    eDataOut,
+    eDataIn,
+    eCSW,
+    eStalled
+} EBotState;
+
+
+#define CBW_SIGNATURE    0x43425355        /**< magic word in CBW */
+#define CSW_SIGNATURE    0x53425355        /**< magic word in CSW */
+
+#define STATUS_PASSED        0x00        /**< successful transfer */
+#define STATUS_FAILED        0x01        /**< failed transfer */
+#define STATUS_PHASE_ERR    0x02        /**< conflict between host and device */
+
+static uint32_t            dwTransferSize;        /**< total size of data transfer */
+static uint32_t            dwOffset;            /**< offset in current data transfer */
+
+static TCBW            CBW;
+static TCSW            CSW;
+
+static EBotState    eState;
+
+static uint8_t            *pbData;
+
+
+
+/**
+    Resets the BOT state machine
+ */
+void MSCBotReset(void)
+{
+    DBG("BOT reset in state %d\n", eState);
+    // reset BOT state
+    eState = eCBW;
+    // reset SCSI
+    SCSIReset();
+}
+
+
+/**
+    Prepares a CSW, to be sent on next bulk-IN interrupt
+        
+    @param [in]    bStatus    CSW status
+ */
+static void SendCSW(uint8_t bStatus)
+{
+    int iResidue;
+    
+    iResidue = CBW.dwCBWDataTransferLength - dwTransferSize;
+    
+    // construct CSW
+    CSW.dwCSWSignature        = CSW_SIGNATURE;
+    CSW.dwCSWTag             = CBW.dwCBWTag;
+    CSW.dwCSWDataResidue     = MAX(iResidue, 0);
+    CSW.bmCSWStatus         = bStatus;
+
+    DBG("CSW: status=%x, residue=%d\n", bStatus, CSW.dwCSWDataResidue);
+
+    // next state
+    eState = eCSW;
+}
+
+
+/**
+    Checks if CBW is valid and meaningful
+        
+    @param [in]    pCBW    Command block wrapper
+    @param [in]    iLen    Length of CBW
+            
+    @return true if valid and meaningful
+ */
+static bool CheckCBW(TCBW *pCBW, int iLen)
+{
+    // CBW valid?
+    if (iLen != 31) {
+        DBG("Invalid length (%d)\n", iLen);
+        return false;
+    }
+    if (pCBW->dwCBWSignature != CBW_SIGNATURE) {
+        DBG("Invalid signature %x\n", pCBW->dwCBWSignature);
+        return false;
+    }
+
+    // CBW meaningful?
+    if (pCBW->bCBWLun != 0) {
+        DBG("Invalid LUN %d\n", pCBW->bCBWLun);
+        return false;
+    }
+    if ((pCBW->bCBWCBLength < 1) || (pCBW->bCBWCBLength > 16)) {
+        DBG("Invalid CB len %d\n", pCBW->bCBWCBLength);
+        return false;
+    }
+    return true;
+}
+
+
+/*************************************************************************
+    BOTStall
+    ========
+        Local function to stall ongoing transfer
+        
+    Which endpoint to stall is determined by looking at the transfer
+    direction intended by the host.
+
+**************************************************************************/
+static void BOTStall(void)
+{
+    if ((CBW.bmCBWFlags & 0x80) || (CBW.dwCBWDataTransferLength == 0)) {
+        // stall data-in or CSW
+        usbdev.stallEndpoint(EPBULK_IN);
+    }
+    else {
+        // stall data-out
+        usbdev.stallEndpoint(EPBULK_OUT);
+    }
+}
+
+
+/*************************************************************************
+    HandleDataIn
+    ============
+        Handles data from device-to-host
+        
+**************************************************************************/
+static void HandleDataIn(int io)
+{
+    int iChunk;
+    // process data for host in SCSI layer
+    pbData = SCSIHandleData(CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset);
+    if (pbData == NULL) {
+        BOTStall();
+        SendCSW(STATUS_FAILED);
+        return;
+    }
+
+    // send data to host?
+    if (dwOffset < dwTransferSize) {
+        iChunk = MIN(64, dwTransferSize - dwOffset);
+        //USBHwEPWrite(MSC_BULK_IN_EP, pbData, iChunk);
+        usbdev.writeNB(EPBULK_IN, pbData, iChunk, MAX_PACKET_SIZE_EPBULK);
+        dwOffset += iChunk;
+    }
+    
+    // are we done now?
+    if (dwOffset == dwTransferSize) {
+        if (dwOffset != CBW.dwCBWDataTransferLength) {
+            // stall pipe
+            DBG("stalling DIN");
+            BOTStall();
+        }
+        // done
+        SendCSW(STATUS_PASSED);
+    }
+}
+
+
+/*************************************************************************
+    HandleDataOut
+    =============
+        Handles data from host-to-device
+        
+**************************************************************************/
+static void HandleDataOut(void)
+{
+    int iChunk;
+    
+    if (dwOffset < dwTransferSize) {
+        // get data from host
+//        iChunk = USBHwEPRead(MSC_BULK_OUT_EP, pbData, dwTransferSize - dwOffset);
+        usbdev.read(EPBULK_OUT, pbData, (uint16_t*)&iChunk, MAX_PACKET_SIZE_EPBULK);
+        // process data in SCSI layer
+        pbData = SCSIHandleData(CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset);
+        if (pbData == NULL) {
+            BOTStall();
+            SendCSW(STATUS_FAILED);
+            return;
+        }
+        dwOffset += iChunk;
+    }
+    
+    // are we done now?
+    if (dwOffset == dwTransferSize) {
+        if (dwOffset != CBW.dwCBWDataTransferLength) {
+            // stall pipe
+            DBG("stalling DOUT");
+            BOTStall();
+        }
+        SendCSW(STATUS_PASSED);
+    }
+}
+        
+        
+/**
+    Handles the BOT bulk OUT endpoint
+        
+    @param [in]    bEP            Endpoint number
+    @param [in]    bEPStatus    Endpoint status (indicates NAK, STALL, etc)
+        
+ */
+void MSCBotBulkOut()
+{
+    int     iLen, iChunk;
+    bool    fHostIn, fDevIn;
+    
+    switch (eState) {
+
+    case eCBW:
+        //iLen = USBHwEPRead(bEP, (U8 *)&CBW, sizeof(CBW));
+        usbdev.read(EPBULK_OUT, (uint8_t *)&CBW, (uint16_t*)&iLen, MAX_PACKET_SIZE_EPBULK);
+
+        // check if we got a good CBW
+        if (!CheckCBW(&CBW, iLen)) {
+            // see 6.6.1
+            usbdev.stallEndpoint(EPBULK_IN);
+            usbdev.stallEndpoint(EPBULK_OUT);
+            eState = eStalled;
+            break;
+        }
+        
+        DBG("CBW: len=%d, flags=%x, cmd=%x, cmdlen=%d\n",
+            CBW.dwCBWDataTransferLength, CBW.bmCBWFlags, CBW.CBWCB[0], CBW.bCBWCBLength);
+        
+        dwOffset = 0;
+        dwTransferSize = 0;
+        fHostIn = ((CBW.bmCBWFlags & 0x80) != 0);
+        
+        // verify request
+        pbData = SCSIHandleCmd(CBW.CBWCB, CBW.bCBWCBLength, &iLen, &fDevIn);
+        if (pbData == NULL) {
+            // unknown command
+            BOTStall();
+            SendCSW(STATUS_FAILED);
+            break;            
+        }
+
+        // rule: if device and host disagree on direction, send CSW with status 2
+        if ((iLen > 0) &&
+            ((fHostIn && !fDevIn) ||
+            (!fHostIn && fDevIn))) {
+            DBG("Host and device disagree on direction\n");
+            BOTStall();
+            SendCSW(STATUS_PHASE_ERR);
+            break;
+        }
+
+        // rule: if D > H, send CSW with status 2
+        if (iLen > CBW.dwCBWDataTransferLength) {
+            DBG("Negative residue\n");
+            BOTStall();
+            SendCSW(STATUS_PHASE_ERR);
+            break;
+        }
+
+        dwTransferSize = iLen;
+        if ((dwTransferSize == 0) || fDevIn) {
+            // data from device-to-host
+            eState = eDataIn;
+            HandleDataIn(0);
+        }
+        else {
+            // data from host-to-device
+            eState = eDataOut;
+        }
+        break;
+        
+    case eDataOut:
+        HandleDataOut();
+        break;
+        
+    case eDataIn:
+    case eCSW:
+//        iChunk = USBHwEPRead(bEP, NULL, 0);
+        uint8_t dummy[64];
+        int idummy;
+        usbdev.read(EPBULK_OUT, dummy, (uint16_t*)&idummy, MAX_PACKET_SIZE_EPBULK);
+        DBG("Phase error in state %d, %d bytes\n", eState, iChunk);
+        eState = eCBW;
+        break;
+    
+    case eStalled:
+        // keep stalling
+        usbdev.stallEndpoint(EPBULK_OUT);
+        break;
+        
+    default:
+        DBG("Invalid state %d\n", eState);
+        break;
+    }
+}
+
+
+/**
+    Handles the BOT bulk IN endpoint
+        
+    @param [in]    bEP            Endpoint number
+    @param [in]    bEPStatus    Endpoint status (indicates NAK, STALL, etc)
+        
+ */
+void MSCBotBulkIn()
+{
+    DBG("MSCBotBulkIn: %d\r\n", eState);
+    switch (eState) {
+    
+    case eCBW:
+    case eDataOut:
+        // ignore possibly old ACKs
+        break;
+    
+    case eDataIn:
+        HandleDataIn(1);
+        break;
+    
+    case eCSW:
+        // wait for an IN token, then send the CSW
+        //USBHwEPWrite(MSC_BULK_IN_EP, (uint8_t *)&CSW, 13);
+        usbdev.writeNB(EPBULK_IN, (uint8_t *)&CSW, 13, MAX_PACKET_SIZE_EPBULK);
+        eState = eCBW;
+        break;
+        
+    case eStalled:
+        // keep stalling
+        usbdev.stallEndpoint(EPBULK_IN);
+        break;
+        
+    default:
+        DBG("Invalid state %d\n", eState);
+        break;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/msc_bot.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,36 @@
+/*
+    LPCUSB, an USB device driver for LPC microcontrollers    
+    Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. The name of the author may not be used to endorse or promote products
+       derived from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mbed.h"
+
+//#define MSC_BULK_OUT_EP        0x02
+//#define MSC_BULK_IN_EP        0x85
+
+void MSCBotReset(void);
+void MSCBotBulkOut();
+void MSCBotBulkIn();
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/msc_scsi.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,370 @@
+/*
+    LPCUSB, an USB device driver for LPC microcontrollers    
+    Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. The name of the author may not be used to endorse or promote products
+       derived from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+    @file
+
+    This is the SCSI layer of the USB mass storage application example.
+    This layer depends directly on the blockdev layer.
+    
+    Windows peculiarities:
+    * Size of REQUEST SENSE CDB is 12 bytes instead of expected 6
+    * Windows requires VERIFY(10) command to do a format.
+      This command is not mandatory in the SBC/SBC-2 specification.
+*/
+/*
+ *  Modified for mbed NXP LPC1768 & LPCXpresso board
+ *  original    LPC214x USB stack beta by bertrik
+ *              target-20070727.tar.gr (119.5KB)
+ *              http://sourceforge.net/projects/lpcusb/
+ *  By Kenji Arai / JH1PJL on September 25th, 2010
+ *      October 3rd, 2010
+ */
+#define FATFS
+
+//#define DEBUG
+#include "dbg.h"
+#include "mbed.h"
+#include <string.h>        // memcpy
+
+#include "blockdev.h"
+#include "msc_scsi.h"
+
+//#include "SDFileSystem.h"
+//extern SDFileSystem sd;
+
+#define BLOCKSIZE        512
+
+// SBC2 mandatory SCSI commands
+#define    SCSI_CMD_TEST_UNIT_READY    0x00
+#define SCSI_CMD_REQUEST_SENSE        0x03
+#define SCSI_CMD_FORMAT_UNIT        0x04
+#define SCSI_CMD_READ_6                0x08    /* not implemented yet */
+#define SCSI_CMD_INQUIRY            0x12
+#define SCSI_CMD_SEND_DIAGNOSTIC    0x1D    /* not implemented yet */
+#define SCSI_CMD_READ_CAPACITY_10    0x25
+#define SCSI_CMD_READ_10            0x28
+#define SCSI_CMD_REPORT_LUNS        0xA0    /* not implemented yet */
+
+// SBC2 optional SCSI commands
+#define SCSI_CMD_WRITE_6            0x0A    /* not implemented yet */
+#define SCSI_CMD_WRITE_10            0x2A
+#define SCSI_CMD_VERIFY_10            0x2F    /* required for windows format */
+
+// sense codes
+#define WRITE_ERROR                0x030C00
+#define READ_ERROR                0x031100
+#define INVALID_CMD_OPCODE        0x052000
+#define INVALID_FIELD_IN_CDB    0x052400
+
+//    Sense code, which is set on error conditions
+static uint32_t            dwSense;    // hex: 00aabbcc, where aa=KEY, bb=ASC, cc=ASCQ
+
+static const uint8_t        abInquiry[] = {
+    0x00,        // PDT = direct-access device
+    0x80,        // removeable medium bit = set
+    0x05,        // version = complies to SPC3
+    0x02,        // response data format = SPC3
+    0x1F,        // additional length
+    0x00,
+    0x00,
+    0x00,
+    'L','P','C','U','S','B',' ',' ',    // vendor
+    'M','a','s','s',' ','s','t','o',    // product
+    'r','a','g','e',' ',' ',' ',' ',
+    '0','.','1',' '                        // revision
+};
+
+//    Data for "request sense" command. The 0xFF are filled in later
+static const uint8_t abSense[] = { 0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A, 
+                              0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+                              0x00, 0x00 };
+
+//    Buffer for holding one block of disk data
+static uint8_t abBlockBuf[512];
+
+
+struct TCDB6 {
+    uint8_t        bOperationCode;
+    uint8_t        abLBA[3];
+    uint8_t        bLength;
+    uint8_t        bControl;
+} __attribute__((packed));
+
+
+/*************************************************************************
+    SCSIReset
+    =========
+        Resets any SCSI state
+        
+**************************************************************************/
+void SCSIReset(void)
+{
+    dwSense = 0;
+}
+
+
+/*************************************************************************
+    SCSIHandleCmd
+    =============
+        Verifies a SCSI CDB and indicates the direction and amount of data
+        that the device wants to transfer.
+        
+    If this call fails, a sense code is set in dwSense.
+
+    IN        pbCDB        Command data block
+            iCDBLen        Command data block len
+    OUT        *piRspLen    Length of intended response data:
+            *pfDevIn    true if data is transferred from device-to-host
+    
+    Returns a pointer to the data exchange buffer if successful,
+    return NULL otherwise.
+**************************************************************************/
+uint8_t * SCSIHandleCmd(uint8_t *pbCDB, uint8_t iCDBLen, int *piRspLen, bool *pfDevIn)
+{
+    static const uint8_t aiCDBLen[] = {6, 10, 10, 0, 16, 12, 0, 0};
+    int        i;
+    TCDB6    *pCDB;
+    uint32_t        dwLen, dwLBA;
+    uint8_t        bGroupCode;
+    
+    pCDB = (TCDB6 *)pbCDB;
+    
+    // default direction is from device to host
+    *pfDevIn = true;
+    
+    // check CDB length
+    bGroupCode = (pCDB->bOperationCode >> 5) & 0x7;
+    if (iCDBLen < aiCDBLen[bGroupCode]) {
+        DBG("Invalid CBD len (expected %d)!\n", aiCDBLen[bGroupCode]);
+        return NULL;
+    }
+
+    switch (pCDB->bOperationCode) {
+
+    // test unit ready (6)
+    case SCSI_CMD_TEST_UNIT_READY:
+        DBG("TEST UNIT READY\n");
+        *piRspLen = 0;
+        break;
+    
+    // request sense (6)
+    case SCSI_CMD_REQUEST_SENSE:
+        DBG("REQUEST SENSE (%06X)\n", dwSense);
+        // check params
+        *piRspLen = MIN(18, pCDB->bLength);
+        break;
+    
+    case SCSI_CMD_FORMAT_UNIT:
+        DBG("FORMAT UNIT %02X\n", pbCDB[1]);
+        *piRspLen = 0;
+        break;
+    
+    // inquiry (6)
+    case SCSI_CMD_INQUIRY:
+        DBG("INQUIRY\n");
+        // see SPC3r23, 4.3.4.6
+        *piRspLen = MIN(36, pCDB->bLength);
+        break;
+        
+    // read capacity (10)
+    case SCSI_CMD_READ_CAPACITY_10:
+        DBG("READ CAPACITY\n");
+        *piRspLen = 8;
+        break;
+        
+    // read (10)
+    case SCSI_CMD_READ_10:
+        dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+        dwLen = (pbCDB[7] << 8) | pbCDB[8];
+        DBG("READ10, LBA=%d, len=%d\n", dwLBA, dwLen);
+        *piRspLen = dwLen * BLOCKSIZE;
+        break;
+
+    // write (10)
+    case SCSI_CMD_WRITE_10:
+        dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+        dwLen = (pbCDB[7] << 8) | pbCDB[8];
+        DBG("WRITE10, LBA=%d, len=%d\n", dwLBA, dwLen);
+        *piRspLen = dwLen * BLOCKSIZE;
+        *pfDevIn = false;
+        break;
+
+    case SCSI_CMD_VERIFY_10:
+        DBG("VERIFY10\n");
+        if ((pbCDB[1] & (1 << 1)) != 0) {
+            // we don't support BYTCHK
+            DBG("BYTCHK not supported\n");
+            return NULL;
+        }
+        *piRspLen = 0;
+        break;
+    
+    default:
+        DBG("Unhandled SCSI: ");        
+        for (i = 0; i < iCDBLen; i++) {
+            DBG(" %02X", pbCDB[i]);
+        }
+        DBG("\n");
+        // unsupported command
+        dwSense = INVALID_CMD_OPCODE;
+        *piRspLen = 0;
+        return NULL;
+    }
+    
+    
+    return abBlockBuf;
+}
+
+
+/*************************************************************************
+    SCSIHandleData
+    ==============
+        Handles a block of SCSI data.
+        
+    IN        pbCDB        Command data block
+            iCDBLen        Command data block len
+    IN/OUT    pbData        Data buffer
+    IN        dwOffset    Offset in data
+    
+    Returns a pointer to the next data to be exchanged if successful,
+    returns NULL otherwise.
+**************************************************************************/
+uint8_t * SCSIHandleData(uint8_t *pbCDB, uint8_t iCDBLen, uint8_t *pbData, uint32_t dwOffset)
+{
+    TCDB6    *pCDB;
+    uint32_t        dwLBA;
+    uint32_t        dwBufPos, dwBlockNr;
+    uint32_t        dwDevSize, dwMaxBlock;
+    
+    pCDB = (TCDB6 *)pbCDB;
+    
+    switch (pCDB->bOperationCode) {
+
+    // test unit ready
+    case SCSI_CMD_TEST_UNIT_READY:
+        if (dwSense != 0) {
+            return NULL;
+        }
+        break;
+    
+    // request sense
+    case SCSI_CMD_REQUEST_SENSE:
+        memcpy(pbData, abSense, 18);
+        // fill in KEY/ASC/ASCQ
+        pbData[2] = (dwSense >> 16) & 0xFF;
+        pbData[12] = (dwSense >> 8) & 0xFF;
+        pbData[13] = (dwSense >> 0) & 0xFF;
+        // reset sense data
+        dwSense = 0;
+        break;
+    
+    case SCSI_CMD_FORMAT_UNIT:
+        // nothing to do, ignore this command
+        break;
+    
+    // inquiry
+    case SCSI_CMD_INQUIRY:
+        memcpy(pbData, abInquiry, sizeof(abInquiry));
+        break;
+        
+    // read capacity
+    case SCSI_CMD_READ_CAPACITY_10:
+#ifdef FATFS
+        // get size of drive (bytes)
+        dwDevSize = BlockDevGetSize();
+//        dwDevSize = sd.disk_sectors() * 512;
+#else
+        // get size of drive (bytes)
+        BlockDevGetSize(&dwDevSize);
+#endif
+        // calculate highest LBA
+        dwMaxBlock = (dwDevSize - 1) / 512;
+        
+        pbData[0] = (dwMaxBlock >> 24) & 0xFF;
+        pbData[1] = (dwMaxBlock >> 16) & 0xFF;
+        pbData[2] = (dwMaxBlock >> 8) & 0xFF;
+        pbData[3] = (dwMaxBlock >> 0) & 0xFF;
+        pbData[4] = (BLOCKSIZE >> 24) & 0xFF;
+        pbData[5] = (BLOCKSIZE >> 16) & 0xFF;
+        pbData[6] = (BLOCKSIZE >> 8) & 0xFF;
+        pbData[7] = (BLOCKSIZE >> 0) & 0xFF;
+        break;
+        
+    // read10
+    case SCSI_CMD_READ_10:
+        dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+
+        // copy data from block buffer
+        dwBufPos = (dwOffset & (BLOCKSIZE - 1));
+        if (dwBufPos == 0) {
+            // read new block
+            dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
+            DBG("R");
+            if (BlockDevRead(dwBlockNr, abBlockBuf)) {
+//            if (sd.disk_read((char*)abBlockBuf, dwBlockNr)) {
+                dwSense = READ_ERROR;
+                DBG("BlockDevRead failed\n");
+                return NULL;
+            }
+        }
+        // return pointer to data
+        return abBlockBuf + dwBufPos;
+
+    // write10
+    case SCSI_CMD_WRITE_10:
+        dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+        
+        // copy data to block buffer
+        dwBufPos = ((dwOffset + 64) & (BLOCKSIZE - 1));
+        if (dwBufPos == 0) {
+            // write new block
+            dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
+            DBG("W");
+            if (BlockDevWrite(dwBlockNr, abBlockBuf)) {
+//            if (sd.disk_write((char*)abBlockBuf, dwBlockNr)) {
+                dwSense = WRITE_ERROR;
+                DBG("BlockDevWrite failed\n");
+                return NULL;
+            }
+        }
+        // return pointer to next data
+        return abBlockBuf + dwBufPos;
+        
+    case SCSI_CMD_VERIFY_10:
+        // dummy implementation
+        break;
+        
+    default:
+        // unsupported command
+        dwSense = INVALID_CMD_OPCODE;
+        return NULL;
+    }
+    
+    // default: return pointer to start of block buffer
+    return abBlockBuf;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/msc_scsi.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,35 @@
+/*
+    LPCUSB, an USB device driver for LPC microcontrollers    
+    Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. The name of the author may not be used to endorse or promote products
+       derived from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
+    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mbed.h"
+
+#define MIN(x,y)    ((x)<(y)?(x):(y))    /**< MIN */
+#define MAX(x,y)    ((x)>(y)?(x):(y))    /**< MAX */
+
+void    SCSIReset(void);
+uint8_t * SCSIHandleCmd(uint8_t *pbCDB, uint8_t bCDBLen, int *piRspLen, bool *pfDevIn);
+uint8_t * SCSIHandleData(uint8_t *pbCDB, uint8_t bCDBLen, uint8_t *pbData, uint32_t dwOffset);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wavplayer.cpp	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,153 @@
+/*
+ Library wave file player by Tom Coxon
+
+ Based on WAVEplayer by Vlad Cazan/Stephan Rochon modified by Tom Coxon to:
+
+ 1. Run correctly on the Embedded Artists LPCXpresso baseboard.
+ 2. To play 8 bit sample size in addition to original 16 bit
+ 3. To be more fault tolerant when playing wav files.
+*/
+
+#include "wavplayer.h"
+
+Ticker tick;
+
+AnalogOut DACout(p18);
+
+void WavPlayer::dac_out() {
+    if (DAC_on) {
+        DACout.write_u16(DAC_fifo[DAC_rptr]);
+        DAC_rptr=(DAC_rptr+1) & 0xff;
+    }
+}
+
+//void play_wave(char *wavname) {
+void WavPlayer::play_wave(char *wavname) {
+    unsigned chunk_id,chunk_size,channel;
+    unsigned data,samp_int,i;
+    short dac_data;
+    char *slice_buf;
+    short *data_sptr;
+    FMT_STRUCT wav_format;
+    FILE *wavfile;
+    long slice,num_slices;
+    DAC_wptr=0;
+    DAC_rptr=0;
+
+    size_t result;
+
+    for (i=0;i<256;i+=2) {
+        DAC_fifo[i]=0;
+        DAC_fifo[i+1]=3000;
+    }
+    DAC_wptr=4;
+    DAC_on=0;
+
+    printf("Playing wave file '%s'\r\n",wavname);
+
+    wavfile=fopen(wavname,"rb");
+    if (!wavfile) {
+        printf("Unable to open wav file '%s'\r\n",wavname);
+        exit(1);
+    }
+
+    fread(&chunk_id,4,1,wavfile);
+    fread(&chunk_size,4,1,wavfile);
+    while (!feof(wavfile)) {
+        printf("Read chunk ID 0x%x, size 0x%x\r\n",chunk_id,chunk_size);
+        switch (chunk_id) {
+            case 0x46464952:
+                fread(&data,4,1,wavfile);
+                printf("RIFF chunk\r\n");
+                printf("  chunk size %d (0x%x)\r\n",chunk_size,chunk_size);
+                printf("  RIFF type 0x%x\r\n",data);
+                break;
+            case 0x20746d66:
+                fread(&wav_format,sizeof(wav_format),1,wavfile);
+                printf("FORMAT chunk\r\n");
+                printf("  chunk size %d (0x%x)\r\n",chunk_size,chunk_size);
+                printf("  compression code %d\r\n",wav_format.comp_code);
+                printf("  %d channels\r\n",wav_format.num_channels);
+                printf("  %d samples/sec\r\n",wav_format.sample_rate);
+                printf("  %d bytes/sec\r\n",wav_format.avg_Bps);
+                printf("  block align %d\r\n",wav_format.block_align);
+                printf("  %d bits per sample\r\n",wav_format.sig_bps);
+                if (chunk_size > sizeof(wav_format))
+                    fseek(wavfile,chunk_size-sizeof(wav_format),SEEK_CUR);
+// create a slice buffer large enough to hold multiple slices
+                slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE);
+                if (!slice_buf) {
+                    printf("Unable to malloc slice buffer");
+                    exit(1);
+                }
+                break;
+            case 0x61746164:
+                slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE);
+                if (!slice_buf) {
+                    printf("Unable to malloc slice buffer");
+                    exit(1);
+                }
+                num_slices=chunk_size/wav_format.block_align;
+                printf("DATA chunk\r\n");
+                printf("  chunk size %d (0x%x)\r\n",chunk_size,chunk_size);
+                printf("  %d slices\r\n",num_slices);
+                printf("  Ideal sample interval=%d\r\n",(unsigned)(1000000.0/wav_format.sample_rate));
+                samp_int=1000000/(wav_format.sample_rate);
+                printf("  programmed interrupt tick interval=%d\r\n",samp_int);
+
+// starting up ticker to write samples out -- no printfs until tick.detach is called
+                tick.attach_us(this,&WavPlayer::dac_out, samp_int);
+                DAC_on=1;
+                for (slice=0;slice<num_slices;slice+=SLICE_BUF_SIZE) {
+
+                    result = fread(slice_buf,wav_format.block_align*SLICE_BUF_SIZE,1,wavfile);
+                    if (feof(wavfile)) {
+                        printf("Oops -- not enough slices in the wave file\r\n");
+
+                        break;
+                    }
+
+                    data_sptr=(short *)slice_buf;
+                    for (i=0;i<SLICE_BUF_SIZE;i++) {
+                        dac_data=0;
+
+// for a stereo wave file average the two channels.
+                        for (channel=0;channel<wav_format.num_channels;channel++) {
+                            switch (wav_format.sig_bps) {
+                                case 16:
+                                    dac_data+=(  ((int)(*data_sptr++)) +32768 );
+                                    break;
+                                case 8:
+                                    dac_data+=(  ((int)(*data_sptr++)) +32768 <<8);
+                                    break;
+                            }
+                        }
+                        DAC_fifo[DAC_wptr]=dac_data;
+                        DAC_wptr=(DAC_wptr+1) & 0xff;
+                        while (DAC_wptr==DAC_rptr) {
+                            wait_us(10);
+                        }
+                    }
+                }
+                DAC_on=0;
+                tick.detach();
+                printf("Ticker detached\r\n");
+                free(slice_buf);
+                break;
+            case 0x5453494c:
+                printf("INFO chunk, size %d\r\n",chunk_size);
+                fseek(wavfile,chunk_size,SEEK_CUR);
+                break;
+            default:
+                printf("unknown chunk type 0x%x, size %d\r\n",chunk_id,chunk_size);
+                data=fseek(wavfile,chunk_size,SEEK_CUR);
+                break;
+        }
+        fread(&chunk_id,4,1,wavfile);
+        fread(&chunk_size,4,1,wavfile);
+    }
+    printf("++++++++++++ Done with wave file ++++++++++\r\n");
+    fclose(wavfile);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wavplayer.h	Tue Nov 22 05:45:58 2011 +0000
@@ -0,0 +1,51 @@
+/*
+ Library wave file player by Tom Coxon
+
+ Based on WAVEplayer by Vlad Cazan/Stephan Rochon modified by Tom Coxon to:
+
+ 1. Run correctly on the Embedded Artists LPCXpresso baseboard.
+ 2. To play 8 bit sample size in addition to original 16 bit
+ 3. To be more fault tolerant when playing wav files.
+*/
+
+#ifndef WAVPLAYER_H
+#define WAVPLAYER_H
+
+#include "mbed.h"
+
+#define SAMPLE_FREQ 40000
+#define BUF_SIZE (SAMPLE_FREQ/10)
+#define SLICE_BUF_SIZE 1
+
+typedef struct uFMT_STRUCT {
+    short comp_code;
+    short num_channels;
+    unsigned sample_rate;
+    unsigned avg_Bps;
+    short block_align;
+    short sig_bps;
+} FMT_STRUCT;
+
+class WavPlayer {
+
+public:
+
+    void play_wave(char *wavname);
+
+private:
+
+    void cleanup(char *);
+    void fill_adc_buf(short *, unsigned);
+    void swapword(unsigned *);
+
+// a FIFO for the DAC
+    short DAC_fifo[256];
+    short DAC_wptr;
+    short DAC_rptr;
+    short DAC_on;
+
+    void dac_out();
+
+};
+
+#endif