USB MSD using the AHBSRAM banks 0 and 1 to create a 32k RAM disk. After FAT format 12kb is writable
Dependencies: USBDevice USBMSD_RAM mbed
Fork of USB-MSD_SD_HelloWorld_Mbed-RAMVersion by
Revision 7:6494da2a5c60, committed 2011-11-14
- Comitter:
- samux
- Date:
- Mon Nov 14 12:08:32 2011 +0000
- Parent:
- 6:126c4d980196
- Child:
- 8:534fd41d8cc7
- Commit message:
- will try to use ChaNFSSD
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ChaNFS/.lib Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/NeoBelerophon/libraries/ChaNFS/llxkji \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ChaNFS/CHAN_FS/diskio.c Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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/.lib Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/NeoBelerophon/libraries/ChaNFSSD/llyfwh \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ChaNFSSD/SDFileSystem.cpp Mon Nov 14 12:08:32 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 Mon Nov 14 12:08:32 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/USBDevice.lib Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/samux/libraries/USBDevice/m0nepw \ No newline at end of file
--- a/USBDevice/.lib Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/samux/libraries/USBDevice/m0hrm9 \ No newline at end of file
--- a/USBDevice/USBDevice/USBBusInterface.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* 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); - -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){}; - virtual void SOF(int frameNumber){}; - virtual bool EP1_OUT_callback(){return false;}; - virtual bool EP1_IN_callback(){return false;}; - virtual bool EP2_OUT_callback(){return false;}; - virtual bool EP2_IN_callback(){return false;}; - virtual bool EP3_OUT_callback(){return false;}; - virtual bool EP3_IN_callback(){return false;}; - -private: - void usbisr(void); - static void _usbisr(void); - static USBHAL * instance; -}; -#endif - -
--- a/USBDevice/USBDevice/USBBusInterface_LPC11U.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,699 +0,0 @@ -// 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 � 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); - - // 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; - - // 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; - - //attach IRQ handler and enable interrupts - 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) { - uint8_t bf = 0; - - //check which buffer must be filled - if (LPC_USB->EPBUFCFG & EP(endpoint)) { - // Double buffered - if (LPC_USB->EPINUSE & EP(endpoint)) { - bf = 1; - } else { - bf = 0; - } - } - - //Active the endpoint for reading - ep[PHY_TO_LOG(endpoint)].out[bf] = 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) { - - uint8_t bf = 0; - - if (!(epComplete & EP(endpoint))) - return EP_PENDING; - else { - epComplete &= ~EP(endpoint); - - //check which buffer has been filled - if (LPC_USB->EPBUFCFG & EP(endpoint)) { - // Double buffered (here we read the previous buffer which was used) - if (LPC_USB->EPINUSE & EP(endpoint)) { - bf = 0; - } else { - bf = 1; - } - } - - // Find how many bytes were read - *bytesRead = (uint32_t) (endpointState[endpoint].maxPacket - BYTES_REMAINING(ep[PHY_TO_LOG(endpoint)].out[bf])); - - // 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 - 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; - - 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 - 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(EP1_IN_callback()) - epComplete &= ~EP(EP1IN); - } - - if (LPC_USB->INTSTAT & EP(EP1OUT)) { - // Clear EP1OUT interrupt - LPC_USB->INTSTAT = EP(EP1OUT); - epComplete |= EP(EP1OUT); - if(EP1_OUT_callback()) - epComplete &= ~EP(EP1OUT); - } - - if (LPC_USB->INTSTAT & EP(EP2IN)) { - // Clear EPBULK_IN interrupt - LPC_USB->INTSTAT = EP(EP2IN); - epComplete |= EP(EP2IN); - if(EP2_IN_callback()) - epComplete &= ~EP(EP2IN); - } - - if (LPC_USB->INTSTAT & EP(EP2OUT)) { - // Clear EPBULK_OUT interrupt - LPC_USB->INTSTAT = EP(EP2OUT); - epComplete |= EP(EP2OUT); - //Call callback function. If true, clear epComplete - if(EP2_OUT_callback()) - epComplete &= ~EP(EP2OUT); - } - - if (LPC_USB->INTSTAT & EP(EP3IN)) { - // Clear EP3_IN interrupt - LPC_USB->INTSTAT = EP(EP3IN); - epComplete |= EP(EP3IN); - if(EP3_IN_callback()) - epComplete &= ~EP(EP3IN); - } - - if (LPC_USB->INTSTAT & EP(EP3OUT)) { - // Clear EP3_OUT interrupt - LPC_USB->INTSTAT = EP(EP3OUT); - epComplete |= EP(EP3OUT); - //Call callback function. If true, clear epComplete - if(EP3_OUT_callback()) - epComplete &= ~EP(EP3OUT); - } -} - -#endif \ No newline at end of file
--- a/USBDevice/USBDevice/USBBusInterface_LPC17_LPC23.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,682 +0,0 @@ -// USBBusInterface_LPC17_LPC23.c -// USB Bus Interface for NXP LPC1768 and LPC2368 -// Copyright (c) 2011 ARM Limited. All rights reserved. - -#ifdef TARGET_LPC1768 - -#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::_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) - { - // (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(EP1_IN_callback()) - epComplete &= ~EP(EP1IN); - } - - if (LPC_USB->USBEpIntSt & EP(EP1OUT)) - { - selectEndpointClearInterrupt(EP1OUT); - epComplete |= EP(EP1OUT); - LPC_USB->USBDevIntClr = EP_SLOW; - if(EP1_OUT_callback()) - epComplete &= ~EP(EP1OUT); - } - - if (LPC_USB->USBEpIntSt & EP(EP2IN)) - { - selectEndpointClearInterrupt(EP2IN); - epComplete |= EP(EP2IN); - LPC_USB->USBDevIntClr = EP_SLOW; - if(EP2_IN_callback()) - epComplete &= ~EP(EP2IN); - } - - if (LPC_USB->USBEpIntSt & EP(EP2OUT)) - { - selectEndpointClearInterrupt(EP2OUT); - epComplete |= EP(EP2OUT); - LPC_USB->USBDevIntClr = EP_SLOW; - if(EP2_OUT_callback()) - epComplete &= ~EP(EP2OUT); - } - - if (LPC_USB->USBEpIntSt & EP(EP3IN)) - { - selectEndpointClearInterrupt(EP3IN); - epComplete |= EP(EP3IN); - LPC_USB->USBDevIntClr = EP_SLOW; - if(EP3_IN_callback()) - epComplete &= ~EP(EP3IN); - } - - if (LPC_USB->USBEpIntSt & EP(EP3OUT)) - { - selectEndpointClearInterrupt(EP3OUT); - epComplete |= EP(EP3OUT); - LPC_USB->USBDevIntClr = EP_SLOW; - if(EP3_OUT_callback()) - epComplete &= ~EP(EP3OUT); - } - } -} - -#endif
--- a/USBDevice/USBDevice/USBDescriptor.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* 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)
--- a/USBDevice/USBDevice/USBDevice.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,912 +0,0 @@ -/* 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" */ - -#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; -}
--- a/USBDevice/USBDevice/USBDevice.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/* 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
--- a/USBDevice/USBDevice/USBDevice_Types.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* 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
--- a/USBDevice/USBDevice/USBEndpoints.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* 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
--- a/USBDevice/USBDevice/USBEndpoints_LPC11U.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* 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)
--- a/USBDevice/USBDevice/USBEndpoints_LPC17_LPC23.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* 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 (64) -#define MAX_PACKET_SIZE_EP2 (64) -#define MAX_PACKET_SIZE_EP3 (1023) -#define MAX_PACKET_SIZE_EP4 (64) -#define MAX_PACKET_SIZE_EP5 (64) -#define MAX_PACKET_SIZE_EP6 (1023) -#define MAX_PACKET_SIZE_EP7 (64) -#define MAX_PACKET_SIZE_EP8 (64) -#define MAX_PACKET_SIZE_EP9 (1023) -#define MAX_PACKET_SIZE_EP10 (64) -#define MAX_PACKET_SIZE_EP11 (64) -#define MAX_PACKET_SIZE_EP12 (1023) -#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. */ - -/* Bulk endpoints */ -#define EPBULK_OUT (EP2OUT) -#define EPBULK_IN (EP2IN) -/* Interrupt endpoints */ -#define EPINT_OUT (EP1OUT) -#define EPINT_IN (EP1IN) -/* Isochronous endpoints */ -#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)
--- a/USBDevice/USBHID/USBHID.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,259 +0,0 @@ -// 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; -}
--- a/USBDevice/USBHID/USBHID.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -/* 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); - -protected: - uint16_t reportLength; - - /* - * 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); - -private: - HID_REPORT outputReport; - uint8_t output_length; - uint8_t input_length; -}; - -#endif
--- a/USBDevice/USBHID/USBHID_Types.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* 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
--- a/USBDevice/USBHID/USBKeyboard.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,472 +0,0 @@ -// 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 (148) -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 */ - {0x47, 0}, /* SCROLL_LOCK */ - {0x39, 0}, /* CAPS_LOCK */ - {0x53, 0}, /* NUM_LOCK */ - {0x49, 0}, /* INSERT */ - {0x4a, 0}, /* HOME */ - {0x4b, 0}, /* PAGE_UP */ - {0x4e, 0}, /* PAGE_DOWN */ -}; - -#else -/* UK keyboard */ -#define KEYMAP_SIZE (148) -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 */ - {0x47, 0}, /* SCROLL_LOCK */ - {0x39, 0}, /* CAPS_LOCK */ - {0x53, 0}, /* NUM_LOCK */ - {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; -} - - -bool USBKeyboard::EP1_OUT_callback() { - uint16_t bytesRead = 0; - uint8_t led[65]; - USBDevice::read(EPINT_OUT, led, &bytesRead, MAX_HID_REPORT_SIZE); - if (leds != NULL && led[0] == REPORT_ID_KEYBOARD) { - // We take led[1] because led[0] is the report_id - // led1: NUM_LOCK - // led2: CAPS_LOCK - // led3: SCROLL_LOCK - *leds = (led[1]) & 0x7; - } - // We activate the endpoint to be able to recceive data - if (!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE)) - return false; - return true; -} - - -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; - - if (!send(&report)) { - return false; - } - - report.data[0] = REPORT_ID_VOLUME; - report.data[1] = 0; - - report.length = 2; - - return send(&report); -} -
--- a/USBDevice/USBHID/USBKeyboard.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ -/* 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_SCROLL_LOCK, /* Scroll lock */ - KEY_CAPS_LOCK, /* caps lock */ - KEY_NUM_LOCK, /* num lock */ - 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 leds Leds bus: first: NUM_LOCK, second: CAPS_LOCK, third: SCROLL_LOCK - * @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(BusOut * leds = NULL, uint16_t vendor_id = 0x1235, uint16_t product_id = 0x0010, uint16_t product_release = 0x0001): - USBHID(0, 0, vendor_id, product_id, product_release){ - this->leds = leds; - }; - - /** - * 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(); - - /* - * Called when a data is received on the OUT endpoint. Useful to switch on LED of LOCK keys - * - * @returns if handle by subclass, return true - */ - virtual bool EP1_OUT_callback(); - - private: - //dummy otherwise it doesn,t compile (we must define all methods of an abstract class) - virtual int _getc() { return -1;}; - - // Switch on leds (CAPS LOCK,...) - BusOut * leds; -}; - -#endif -
--- a/USBDevice/USBHID/USBMouse.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -// 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; -} - -
--- a/USBDevice/USBHID/USBMouse.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/* 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
--- a/USBDevice/USBHID/USBMouseKeyboard.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,681 +0,0 @@ -// 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 (148) -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 */ - {0x47, 0}, /* SCROLL_LOCK */ - {0x39, 0}, /* CAPS_LOCK */ - {0x53, 0}, /* NUM_LOCK */ - {0x49, 0}, /* INSERT */ - {0x4a, 0}, /* HOME */ - {0x4b, 0}, /* PAGE_UP */ - {0x4e, 0}, /* PAGE_DOWN */ -}; - -#else -/* UK keyboard */ -#define KEYMAP_SIZE (148) -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 */ - {0x47, 0}, /* SCROLL_LOCK */ - {0x39, 0}, /* CAPS_LOCK */ - {0x53, 0}, /* NUM_LOCK */ - {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::EP1_OUT_callback() { - uint16_t bytesRead = 0; - uint8_t led[65]; - USBDevice::read(EPINT_OUT, led, &bytesRead, MAX_HID_REPORT_SIZE); - if (leds != NULL && led[0] == REPORT_ID_KEYBOARD) { - // We take led[1] because led[0] is the report_id - // led1: NUM_LOCK - // led2: CAPS_LOCK - // led3: SCROLL_LOCK - *leds = (led[1]) & 0x7; - } - // We activate the endpoint to be able to recceive data - if (!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE)) - return false; - return true; -} - -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); -}
--- a/USBDevice/USBHID/USBMouseKeyboard.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -/* 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 leds Leds bus: first: NUM_LOCK, second: CAPS_LOCK, third: SCROLL_LOCK - * @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, BusOut * leds = NULL, uint16_t vendor_id = 0x0021, uint16_t product_id = 0x0011, uint16_t product_release = 0x0001): - USBHID(0, 0, vendor_id, product_id, product_release) - { - this->leds = leds; - 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(); - - /* - * Called when a data is received on the OUT endpoint. Useful to switch on LED of LOCK keys - * - * @returns if handle by subclass, return true - */ - virtual bool EP1_OUT_callback(); - - - 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); - - // Switch on leds (CAPS LOCK,...) - BusOut * leds; - - //dummy otherwise it doesn,t compile (we must define all methods of an abstract class) - virtual int _getc() { return -1;} -}; - -#endif
--- a/USBDevice/USBMIDI/MIDIMessage.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,254 +0,0 @@ -/* @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
--- a/USBDevice/USBMIDI/USBMIDI.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -// 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::EP2_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; -} - - - -// Called in ISR context -// Set configuration. Return false if the -// configuration is not supported. -bool USBMIDI::USBCallback_setConfiguration(uint8_t configuration) { - 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; -}
--- a/USBDevice/USBMIDI/USBMIDI.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* 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); - - /** - * 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)); - - -protected: - virtual bool EP2_OUT_callback(); - virtual bool USBCallback_setConfiguration(uint8_t configuration); - /* - * 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(); - -private: - void (*midi_evt)(MIDIMessage); - -}; - -#endif -
--- a/USBDevice/USBMSD/USBMSD.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,617 +0,0 @@ -// USBMSD.cpp -// USB mass storage device example -// Copyright (c) 2011 ARM Limited. All rights reserved. - -#include "stdint.h" -#include "USBMSD.h" -#include "USBBusInterface.h" - -#define CBW_Signature 0x43425355 -#define CSW_Signature 0x53425355 - -// SCSI Commands -#define TEST_UNIT_READY 0x00 -#define REQUEST_SENSE 0x03 -#define FORMAT_UNIT 0x04 -#define INQUIRY 0x12 -#define MODE_SELECT6 0x15 -#define MODE_SENSE6 0x1A -#define START_STOP_UNIT 0x1B -#define MEDIA_REMOVAL 0x1E -#define READ_FORMAT_CAPACITIES 0x23 -#define READ_CAPACITY 0x25 -#define READ10 0x28 -#define WRITE10 0x2A -#define VERIFY10 0x2F -#define READ12 0xA8 -#define WRITE12 0xAA -#define MODE_SELECT10 0x55 -#define MODE_SENSE10 0x5A - -// MSC class specific requests -#define MSC_REQUEST_RESET 0xFF -#define MSC_REQUEST_GET_MAX_LUN 0xFE - -#define DEFAULT_CONFIGURATION (1) - -// Max In/Out Packet Size on the bulk endpoint */ -#define MAX_PACKET MAX_PACKET_SIZE_EPBULK - -// CSW Status -enum Status { - CSW_PASSED, - CSW_FAILED, - CSW_ERROR, -}; - - -USBMSD::USBMSD(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) { -} - - -DigitalOut l2(LED2); -// Called in ISR context to process a class specific request -bool USBMSD::USBCallback_request(void) { - - bool success = false; - CONTROL_TRANSFER * transfer = getTransferPtr(); - - if (transfer->setup.bmRequestType.Type == CLASS_TYPE) { - switch (transfer->setup.bRequest) { - case MSC_REQUEST_RESET: - reset(); - success = true; - break; - case MSC_REQUEST_GET_MAX_LUN: - transfer->remaining = 1; - transfer->ptr = getMaxLUN(); - transfer->direction = DEVICE_TO_HOST; - success = true; - break; - default: - break; - } - } - - return success; -} - - -bool USBMSD::connect() -{ - - //disk initialization - diskInit(); - - // get block size - BlockSize = blockSize(); - if(BlockSize != 0) { - page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t)); - if(page == NULL) - return false; - } - - //get memory size - MemorySize = memorySize(); - if(!MemorySize) { - return false; - } - BlockCount = MemorySize/BlockSize; - - //connect the device - USBDevice::connect(); - return true; -} - - -void USBMSD::reset() -{ - stage = READ_CBW; -} - -uint8_t * USBMSD::getMaxLUN() -{ - static uint8_t LUN[] = {0}; - return LUN; -} - -// Called in ISR context called when a data is received -bool USBMSD::EP2_OUT_callback() { - uint16_t size = 0; - uint8_t buf[MAX_PACKET_SIZE_EPBULK]; - read(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK); - switch (stage) { - // the device has to decode the CBW received - case READ_CBW: - CBWDecode(buf, size); - break; - - // the device has to receive data from the host - case PROCESS_CBW: - switch (cbw.CB[0]) { - case WRITE10: - case WRITE12: - memoryWrite(buf, size); - break; - case VERIFY10: - memoryVerify(buf, size); - break; - } - break; - - // an error has occured: stall endpoint and send CSW - default: - stallEndpoint(EPBULK_OUT); - csw.Status = CSW_ERROR; - sendCSW(); - break; - } - - //reactivate readings on the OUT bulk endpoint - readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); - return true; -} - -// Called in ISR context when a data has been transferred -bool USBMSD::EP2_IN_callback() { - switch (stage) { - - // the device has to send data to the host - case PROCESS_CBW: - switch (cbw.CB[0]) { - case READ10: - case READ12: - memoryRead(); - break; - } - break; - - //the device has to send a CSW - case SEND_CSW: - sendCSW(); - break; - - // an error has occured - case ERROR: - stallEndpoint(EPBULK_IN); - sendCSW(); - break; - - // the host has received the CSW -> we wait a CBW - case WAIT_CSW: - stage = READ_CBW; - break; - } - return true; -} - - -void USBMSD::memoryWrite (uint8_t * buf, uint16_t size) { - - if ((addr + size) > MemorySize) { - size = MemorySize - addr; - stage = ERROR; - stallEndpoint(EPBULK_OUT); - } - - // we fill an array in RAM of 1 block before writing it in memory - for (int i = 0; i < size; i++) - page[addr%BlockSize + i] = buf[i]; - - // if the array is filled, write it in memory - if (!((addr + size)%BlockSize)) - blockWrite(page, addr/BlockSize); - - addr += size; - length -= size; - csw.DataResidue -= size; - - if ((!length) || (stage != PROCESS_CBW)) { - csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED; - sendCSW(); - } -} - -void USBMSD::memoryVerify (uint8_t * buf, uint16_t size) { - uint32_t n; - - if ((addr + size) > MemorySize) { - size = MemorySize - addr; - stage = ERROR; - stallEndpoint(EPBULK_OUT); - } - - // beginning of a new block -> load a whole block in RAM - if (!(addr%BlockSize)) - blockRead(page, addr/BlockSize); - - // info are in RAM -> no need to re-read memory - for (n = 0; n < size; n++) { - if (page[addr%BlockSize + n] != buf[n]) { - memOK = false; - break; - } - } - - addr += size; - length -= size; - csw.DataResidue -= size; - - if ( !length || (stage != PROCESS_CBW)) { - csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED; - sendCSW(); - } -} - - -bool USBMSD::inquiryRequest (void) { - uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01, - 36 - 4, 0x80, 0x00, 0x00, - 'M', 'B', 'E', 'D', '.', 'O', 'R', 'G', - 'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ', - '1', '.', '0', ' ', - }; - if (!write(inquiry, sizeof(inquiry))) { - return false; - } - return true; -} - - -bool USBMSD::readFormatCapacity() { - uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08, - (BlockCount >> 24) & 0xff, - (BlockCount >> 16) & 0xff, - (BlockCount >> 8) & 0xff, - (BlockCount >> 0) & 0xff, - - 0x02, - (BlockSize >> 16) & 0xff, - (BlockSize >> 8) & 0xff, - (BlockSize >> 0) & 0xff, - }; - if (!write(capacity, sizeof(capacity))) { - return false; - } - return true; -} - - -bool USBMSD::readCapacity (void) { - uint8_t capacity[] = { - ((BlockCount - 1) >> 24) & 0xff, - ((BlockCount - 1) >> 16) & 0xff, - ((BlockCount - 1) >> 8) & 0xff, - ((BlockCount - 1) >> 0) & 0xff, - - (BlockSize >> 24) & 0xff, - (BlockSize >> 16) & 0xff, - (BlockSize >> 8) & 0xff, - (BlockSize >> 0) & 0xff, - }; - if (!write(capacity, sizeof(capacity))) { - return false; - } - return true; -} - -bool USBMSD::write (uint8_t * buf, uint16_t size) { - - if (size >= cbw.DataLength) { - size = cbw.DataLength; - } - stage = SEND_CSW; - - if (!writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) { - return false; - } - - csw.DataResidue -= size; - csw.Status = CSW_PASSED; - return true; -} - - -bool USBMSD::modeSense6 (void) { - uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 }; - if (!write(sense6, sizeof(sense6))) { - return false; - } - return true; -} - -void USBMSD::sendCSW() { - csw.Signature = CSW_Signature; - writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK); - stage = WAIT_CSW; -} - -bool USBMSD::requestSense (void) { - uint8_t request_sense[] = { - 0x70, // Response Code - 0x00, - 0x05, // Sense Key: illegal request - 0x00, - 0x00, - 0x00, - 0x00, - 0x0A, // Additional Length - 0x00, - 0x00, - 0x00, - 0x00, - 0x30, // ASC - 0x01, // ASCQ - 0x00, - 0x00, - 0x00, - 0x00, - }; - - if (!write(request_sense, sizeof(request_sense))) { - return false; - } - - return true; -} - -void USBMSD::fail() { - csw.Status = CSW_FAILED; - sendCSW(); -} - -DigitalOut l1(LED1); -void USBMSD::CBWDecode(uint8_t * buf, uint16_t size) { - if (size == sizeof(cbw)) { - memcpy((uint8_t *)&cbw, buf, size); - if (cbw.Signature == CBW_Signature) { - csw.Tag = cbw.Tag; - csw.DataResidue = cbw.DataLength; - if ((cbw.CBLength < 1) || (cbw.CBLength > 16) ) { - fail(); - } else { - switch (cbw.CB[0]) { - case TEST_UNIT_READY: - testUnitReady(); - break; - case REQUEST_SENSE: - requestSense(); - break; - case INQUIRY: - inquiryRequest(); - break; - case MODE_SENSE6: - modeSense6(); - break; - case READ_FORMAT_CAPACITIES: - readFormatCapacity(); - break; - case READ_CAPACITY: - readCapacity(); - break; - case READ10: - case READ12: - if (infoTransfer()) { - if ((cbw.Flags & 0x80)) { - stage = PROCESS_CBW; - memoryRead(); - } else { - stallEndpoint(EPBULK_OUT); - csw.Status = CSW_ERROR; - sendCSW(); - } - } - break; - case WRITE10: - case WRITE12: - if (infoTransfer()) { - if (!(cbw.Flags & 0x80)) { - stage = PROCESS_CBW; - } else { - stallEndpoint(EPBULK_IN); - csw.Status = CSW_ERROR; - sendCSW(); - } - } - break; - case VERIFY10: - if (!(cbw.CB[1] & 0x02)) { - csw.Status = CSW_PASSED; - sendCSW(); - break; - } - if (infoTransfer()) { - if (!(cbw.Flags & 0x80)) { - stage = PROCESS_CBW; - memOK = true; - } else { - stallEndpoint(EPBULK_IN); - csw.Status = CSW_ERROR; - sendCSW(); - } - } - break; - default: - fail(); - break; - } - } - } - } -} - -void USBMSD::testUnitReady (void) { - - if (cbw.DataLength != 0) { - if ((cbw.Flags & 0x80) != 0) { - stallEndpoint(EPBULK_IN); - } else { - stallEndpoint(EPBULK_OUT); - } - } - - csw.Status = CSW_PASSED; - sendCSW(); -} - - -void USBMSD::memoryRead (void) { - uint32_t n; - - n = (length > MAX_PACKET) ? MAX_PACKET : length; - - if ((addr + n) > MemorySize) { - n = MemorySize - addr; - stage = ERROR; - } - - // we read an entire block - if (!(addr%BlockSize)) - blockRead(page, addr/BlockSize); - - // write data which are in RAM - writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK); - - addr += n; - length -= n; - - csw.DataResidue -= n; - - if ( !length || (stage != PROCESS_CBW)) { - csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED; - sendCSW(); - } -} - - -bool USBMSD::infoTransfer (void) { - uint32_t n; - - // Logical Block Address of First Block - n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] << 8) | (cbw.CB[5] << 0); - - addr = n * BlockSize; - - // Number of Blocks to transfer - switch (cbw.CB[0]) { - case READ10: - case WRITE10: - case VERIFY10: - n = (cbw.CB[7] << 8) | (cbw.CB[8] << 0); - break; - - case READ12: - case WRITE12: - n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] << 8) | (cbw.CB[9] << 0); - break; - } - - length = n * BlockSize; - - if (!cbw.DataLength) { // host requests no data - csw.Status = CSW_FAILED; - sendCSW(); - return false; - } - - if (cbw.DataLength != length) { - if ((cbw.Flags & 0x80) != 0) { - stallEndpoint(EPBULK_IN); - } else { - stallEndpoint(EPBULK_OUT); - } - - csw.Status = CSW_FAILED; - sendCSW(); - return false; - } - - return true; -} - - - - - -// Called in ISR context -// Set configuration. Return false if the -// configuration is not supported. -bool USBMSD::USBCallback_setConfiguration(uint8_t configuration) { - if (configuration != DEFAULT_CONFIGURATION) { - return false; - } - - // Configure endpoints > 0 - addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK); - addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); - - //activate readings - readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); - return true; -} - - -uint8_t * USBMSD::stringIinterfaceDesc() { - static uint8_t stringIinterfaceDescriptor[] = { - 0x08, //bLength - STRING_DESCRIPTOR, //bDescriptorType 0x03 - 'M',0,'S',0,'D',0 //bString iInterface - MSD - }; - return stringIinterfaceDescriptor; -} - -uint8_t * USBMSD::stringIproductDesc() { - static uint8_t stringIproductDescriptor[] = { - 0x12, //bLength - STRING_DESCRIPTOR, //bDescriptorType 0x03 - 'M',0,'b',0,'e',0,'d',0,' ',0,'M',0,'S',0,'D',0 //bString iProduct - Mbed Audio - }; - return stringIproductDescriptor; -} - - -uint8_t * USBMSD::configurationDesc() { - static uint8_t configDescriptor[] = { - - // Configuration 1 - 9, // bLength - 2, // bDescriptorType - LSB(9 + 9 + 7 + 7), // wTotalLength - MSB(9 + 9 + 7 + 7), - 0x01, // bNumInterfaces - 0x01, // bConfigurationValue: 0x01 is used to select this configuration - 0x00, // iConfiguration: no string to describe this configuration - 0xC0, // bmAttributes - 100, // bMaxPower, device power consumption is 100 mA - - // Interface 0, Alternate Setting 0, MSC Class - 9, // bLength - 4, // bDescriptorType - 0x00, // bInterfaceNumber - 0x00, // bAlternateSetting - 0x02, // bNumEndpoints - 0x08, // bInterfaceClass - 0x06, // bInterfaceSubClass - 0x50, // bInterfaceProtocol - 0x04, // iInterface - - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength - 5, // bDescriptorType - PHY_TO_DESC(EPBULK_IN), // bEndpointAddress - 0x02, // bmAttributes (0x02=bulk) - LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) - MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) - 0, // bInterval - - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength - 5, // bDescriptorType - PHY_TO_DESC(EPBULK_OUT), // bEndpointAddress - 0x02, // bmAttributes (0x02=bulk) - LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) - MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) - 0 // bInterval - }; - return configDescriptor; -}
--- a/USBDevice/USBMSD/USBMSD.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,204 +0,0 @@ -/* USBMSD.h */ -/* USB mass storage device example */ -/* Copyright (c) 2011 ARM Limited. All rights reserved. */ - -/* -* Guide to adapt this class to your storage chip: -* -*/ - -#ifndef USBMSD_H -#define USBMSD_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) - - -// MSC Bulk-only Stage -enum Stage { - READ_CBW, // wait a CBW - ERROR, // error - PROCESS_CBW, // process a CBW request - SEND_CSW, // send a CSW - WAIT_CSW, // wait that a CSW has been effectively sent -}; - -// Bulk-only CBW -typedef __packed struct { - uint32_t Signature; - uint32_t Tag; - uint32_t DataLength; - uint8_t Flags; - uint8_t LUN; - uint8_t CBLength; - uint8_t CB[16]; -} CBW; - -// Bulk-only CSW -typedef __packed struct { - uint32_t Signature; - uint32_t Tag; - uint32_t DataResidue; - uint8_t Status; -} CSW; - - -class USBMSD: public USBDevice { -public: - - /** - * Constructor - * - * @param vendor_id Your vendor_id - * @param product_id Your product_id - * @param product_release Your preoduct_release - */ - USBMSD(uint16_t vendor_id = 0x0703, uint16_t product_id = 0x0104, uint16_t product_release = 0x0001); - - /* - * read a block on a storage chip - * - * @param data pointer where will be stored read data - * @param block block number - * @returns 0 if successful - */ - virtual int blockRead(uint8_t * data, uint16_t block){return 1;}; - - /* - * write a block on a storage chip - * - * @param data data to write - * @param block block number - * @returns 0 if successful - */ - virtual int blockWrite(uint8_t * data, uint16_t block){return 1;}; - - /* - * Disk initilization - */ - virtual int diskInit(){return -1;}; - - /* - * Return block size - * - * @returns size of a block - */ - virtual uint16_t blockSize(){return 0;}; - - /* - * Return memory size - * - * @returns memory size - */ - virtual uint32_t memorySize(){return 0;}; - - /* - * Connect the USB MSD device. Establish disk initialization before really connect the device. - * - * @returns - */ - bool connect(); - - -protected: - - - /* - * Get number of logical unit - 1 (here 0) - * - * @returns Pointer containing the number of logical unit - 1 - */ - uint8_t * getMaxLUN(); - - /* - * 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(); - - /* - * Callback called when a packet is received - */ - virtual bool EP2_OUT_callback(); - - /* - * Callback called when a packet has been sent - */ - virtual bool EP2_IN_callback(); - - /* - * Set configuration of device. Add endpoints - */ - virtual bool USBCallback_setConfiguration(uint8_t configuration); - - /* - * Callback called to process class specific requests - */ - virtual bool USBCallback_request(); - - -private: - //state of the bulk-only state machine - Stage stage; - - // current CBW - CBW cbw; - - // CSW which will be sent - CSW csw; - - // addr where will be read or written data - uint32_t addr; - - // length of a reading or writing - uint32_t length; - - // memory OK (after a memoryVerify) - bool memOK; - - // cache in RAM before writing in memory. Useful also to read a block. - uint8_t * page; - - uint16_t BlockSize; - uint32_t MemorySize; - uint16_t BlockCount; - - void CBWDecode(uint8_t * buf, uint16_t size); - void sendCSW (void); - bool inquiryRequest (void); - bool write (uint8_t * buf, uint16_t size); - bool readFormatCapacity(); - bool readCapacity (void); - bool infoTransfer (void); - void memoryRead (void); - bool modeSense6 (void); - void testUnitReady (void); - bool requestSense (void); - void memoryVerify (uint8_t * buf, uint16_t size); - void memoryWrite (uint8_t * buf, uint16_t size); - void reset(); - void fail(); -}; - -#endif
--- a/USBDevice/USBMSD/USB_SDcard.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,374 +0,0 @@ -/* mbed USB_SDcard Library, for accessing 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. - */ - -#include "USB_SDcard.h" - -#define SD_COMMAND_TIMEOUT 5000 - -USB_SDcard::USB_SDcard(PinName mosi, PinName miso, PinName sclk, PinName cs): - _spi(mosi, miso, sclk), _cs(cs) { - _cs = 1; - USBMSD::connect(); -} - -#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 USB_SDcard::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 USB_SDcard::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 USB_SDcard::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; -} - -uint32_t USB_SDcard::memorySize() -{ - return (uint32_t)capacity; -} - -uint16_t USB_SDcard::blockSize() -{ - return (uint16_t)block_len; -} - -int USB_SDcard::diskInit() { - - 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 USB_SDcard::blockWrite(uint8_t * buffer, uint16_t block_number) { - // set write address for single block (CMD24) - if(_cmd(24, block_number * 512) != 0) { - return 1; - } - - // send the data block - _write((const char *)buffer, 512); - return 0; -} - -int USB_SDcard::blockRead(uint8_t * buffer, uint16_t block_number) { - // set read address for single block (CMD17) - if(_cmd(17, block_number * 512) != 0) { - return 1; - } - - // receive the data - _read((char *)buffer, 512); - return 0; -} - -int USB_SDcard::disk_status() { return 0; } -int USB_SDcard::disk_sync() { return 0; } -int USB_SDcard::disk_sectors() { return _sectors; } - -// PRIVATE FUNCTIONS - -int USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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) - - block_len = 1 << read_bl_len; - int mult = 1 << (c_size_mult + 2); - int blocknr = (c_size + 1) * mult; - capacity = blocknr * block_len; - - int blocks = capacity / 512; - - return blocks; -}
--- a/USBDevice/USBMSD/USB_SDcard.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* mbed USB_SDcard Library, for accessing 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 USB_SDCARD_H -#define USB_SDCARD_H - -#include "mbed.h" -#include "USBMSD.h" - -class USB_SDcard : public USBMSD { -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 - */ - USB_SDcard(PinName mosi = p5, PinName miso = p6, PinName sclk = p7, PinName cs = p8); - - /* - * read a block on a storage chip - * - * @param data pointer where will be stored read data - * @param block block number - * @returns 0 if successful - */ - virtual int blockRead(uint8_t * data, uint16_t block); - - /* - * write a block on a storage chip - * - * @param data data to write - * @param block block number - * @returns 0 if successful - */ - virtual int blockWrite(uint8_t * data, uint16_t block); - - virtual int diskInit(); - virtual uint16_t blockSize(); - virtual uint32_t memorySize(); - -protected: - - int disk_status(); - int disk_sync(); - int disk_sectors(); - 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; - int capacity; - int block_len; - - SPI _spi; - DigitalOut _cs; -}; - -#endif
--- a/USBDevice/USBSERIAL/CBuffer.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -#ifndef CBUFFER_H -#define CBUFFER_H - -#define MAX_BUF 128 - -class CBuffer { -public: - CBuffer() { - write = 0; - read = 0; - size = MAX_BUF + 1; - }; - - bool isFull() { - return ((write + 1) % size == read); - }; - - bool isEmpty() { - return (read == write); - }; - - void queue(uint8_t k) { - if (isFull()) { - read++; - read %= size; - } - buf[write++] = k; - write %= size; - } - - uint16_t available() { - return (write >= read) ? write - read : size - read + write; - }; - - bool dequeue(uint8_t * c) { - if (!isEmpty()) { - *c = buf[read++]; - read %= size; - } - return(isEmpty()); - }; - - -private: - volatile uint16_t write; - volatile uint16_t read; - uint16_t size; - uint8_t buf[MAX_BUF + 1]; -}; - -#endif \ No newline at end of file
--- a/USBDevice/USBSERIAL/USBCDC.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,225 +0,0 @@ -/* USBCDC.c */ -/* CDC class */ -/* Copyright (c) 2011 ARM Limited. All rights reserved. */ - -#include "stdint.h" -#include "USBCDC.h" -#include "USBBusInterface.h" - -static uint8_t cdc_line_coding[7]= {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08}; - -#define DEFAULT_CONFIGURATION (1) - -#define CDC_SET_LINE_CODING 0x20 -#define CDC_GET_LINE_CODING 0x21 -#define CDC_SET_CONTROL_LINE_STATE 0x22 - -#define MAX_CDC_REPORT_SIZE MAX_PACKET_SIZE_EPBULK - -USBCDC::USBCDC(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): - USBDevice(vendor_id, product_id, product_release) { } - -bool USBCDC::USBCallback_request(void) { - /* Called in ISR context */ - - bool success = false; - CONTROL_TRANSFER * transfer = getTransferPtr(); - - /* Process class-specific requests */ - - if (transfer->setup.bmRequestType.Type == CLASS_TYPE) { - switch (transfer->setup.bRequest) { - case CDC_GET_LINE_CODING: - transfer->remaining = 7; - transfer->ptr = cdc_line_coding; - transfer->direction = DEVICE_TO_HOST; - success = true; - break; - case CDC_SET_LINE_CODING: - transfer->remaining = 7; - success = true; - break; - case CDC_SET_CONTROL_LINE_STATE: - success = true; - break; - default: - break; - } - } - - return success; -} - - -// Called in ISR context -// Set configuration. Return false if the -// configuration is not supported. -bool USBCDC::USBCallback_setConfiguration(uint8_t configuration) { - if (configuration != DEFAULT_CONFIGURATION) { - return false; - } - - // Configure endpoints > 0 - addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT); - addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK); - addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); - - // We activate the endpoint to be able to recceive data - readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); - return true; -} - -bool USBCDC::send(uint8_t endpoint, uint8_t * buffer, uint16_t size) { - return write(endpoint, buffer, size, MAX_CDC_REPORT_SIZE); -} - -bool USBCDC::read(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize) { - if (!USBDevice::read(endpoint, buffer, size, maxSize)) - return false; - if (!readStart(endpoint, maxSize)) - return false; - return true; -} - -bool USBCDC::readNB(uint8_t endpoint, uint8_t * buffer, uint16_t * size, uint16_t maxSize) { - if (!USBDevice::readNB(endpoint, buffer, size, MAX_CDC_REPORT_SIZE)) - return false; - if (!readStart(endpoint, MAX_CDC_REPORT_SIZE)) - return false; - return true; -} - - -uint8_t * USBCDC::deviceDesc() { - static uint8_t deviceDescriptor[] = { - 18, // bLength - 1, // bDescriptorType - 0x10, 0x01, // bcdUSB - 2, // bDeviceClass - 0, // bDeviceSubClass - 0, // bDeviceProtocol - MAX_PACKET_SIZE_EP0, // bMaxPacketSize0 - LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor - LSB(PRODUCT_ID), MSB(PRODUCT_ID),// idProduct - 0x00, 0x01, // bcdDevice - 1, // iManufacturer - 2, // iProduct - 3, // iSerialNumber - 1 // bNumConfigurations - }; - return deviceDescriptor; -} - -uint8_t * USBCDC::stringIinterfaceDesc() { - static uint8_t stringIinterfaceDescriptor[] = { - 0x08, - STRING_DESCRIPTOR, - 'C',0,'D',0,'C',0, - }; - return stringIinterfaceDescriptor; -} - -uint8_t * USBCDC::stringIproductDesc() { - static uint8_t stringIproductDescriptor[] = { - 0x16, - STRING_DESCRIPTOR, - 'C',0,'D',0,'C',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 - }; - return stringIproductDescriptor; -} - - -#define CONFIG1_DESC_SIZE (9+9+5+5+4+5+7+9+7+7) - -uint8_t * USBCDC::configurationDesc() { - static uint8_t configDescriptor[] = { - 9, // bLength; - 2, // bDescriptorType; - LSB(CONFIG1_DESC_SIZE), // wTotalLength - MSB(CONFIG1_DESC_SIZE), - 2, // bNumInterfaces - 1, // bConfigurationValue - 0, // iConfiguration - 0x80, // bmAttributes - 50, // bMaxPower - - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 - 9, // bLength - 4, // bDescriptorType - 0, // bInterfaceNumber - 0, // bAlternateSetting - 1, // bNumEndpoints - 0x02, // bInterfaceClass - 0x02, // bInterfaceSubClass - 0x01, // bInterfaceProtocol - 0, // iInterface - - // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 - 5, // bFunctionLength - 0x24, // bDescriptorType - 0x00, // bDescriptorSubtype - 0x10, 0x01, // bcdCDC - - // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 - 5, // bFunctionLength - 0x24, // bDescriptorType - 0x01, // bDescriptorSubtype - 0x03, // bmCapabilities - 1, // bDataInterface - - // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 - 4, // bFunctionLength - 0x24, // bDescriptorType - 0x02, // bDescriptorSubtype - 0x06, // bmCapabilities - - // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 - 5, // bFunctionLength - 0x24, // bDescriptorType - 0x06, // bDescriptorSubtype - 0, // bMasterInterface - 1, // bSlaveInterface0 - - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - ENDPOINT_DESCRIPTOR_LENGTH, // bLength - ENDPOINT_DESCRIPTOR, // bDescriptorType - PHY_TO_DESC(EPINT_IN), // bEndpointAddress - E_INTERRUPT, // bmAttributes (0x03=intr) - LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) - MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) - 16, // bInterval - - - - - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 - 9, // bLength - 4, // bDescriptorType - 1, // bInterfaceNumber - 0, // bAlternateSetting - 2, // bNumEndpoints - 0x0A, // bInterfaceClass - 0x00, // bInterfaceSubClass - 0x00, // bInterfaceProtocol - 0, // iInterface - - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength - 5, // bDescriptorType - PHY_TO_DESC(EPBULK_IN), // bEndpointAddress - 0x02, // bmAttributes (0x02=bulk) - LSB(MAX_PACKET_SIZE_EPBULK), // wMaxPacketSize (LSB) - MSB(MAX_PACKET_SIZE_EPBULK), // wMaxPacketSize (MSB) - 0, // bInterval - - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength - 5, // bDescriptorType - PHY_TO_DESC(EPBULK_OUT),// bEndpointAddress - 0x02, // bmAttributes (0x02=bulk) - LSB(MAX_PACKET_SIZE_EPBULK), // wMaxPacketSize (LSB) - MSB(MAX_PACKET_SIZE_EPBULK), // wMaxPacketSize (MSB) - 0 // bInterval - }; - return configDescriptor; -}
--- a/USBDevice/USBSERIAL/USBCDC.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* USBCDC.h */ -/* CDC class */ -/* Copyright (c) 2011 ARM Limited. All rights reserved. */ - -#ifndef USBCDC_H -#define USBCDC_H - -/* These headers are included for child class. */ -#include "USBEndpoints.h" -#include "USBDescriptor.h" -#include "USBDevice_Types.h" - -#include "USBDevice.h" - - - -class USBCDC: public USBDevice { -public: - - /* - * Constructor - * - * @param vendor_id Your vendor_id - * @param product_id Your product_id - * @param product_release Your preoduct_release - */ - USBCDC(uint16_t vendor_id, uint16_t product_id, uint16_t product_release); - - - /* - * 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 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 buffer to a certain endpoint - * - * @param endpoint endpoint which will be sent the buffer - * @param buffer buffer to be sent - * @param size length of the buffer - * @returns true if successful - */ - bool send(uint8_t endpoint, uint8_t * buffer, uint16_t size); - - /* - * Read a buffer from a certain endpoint. Warning: blocking - * - * @param endpoint endpoint to read - * @param buffer buffer where will be stored bytes - * @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 buffer from a certain endpoint. Warning: non blocking - * - * @param endpoint endpoint to read - * @param buffer buffer where will be stored bytes - * @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); - - virtual bool USBCallback_request(); - virtual bool USBCallback_setConfiguration(uint8_t configuration); - -}; - -#endif
--- a/USBDevice/USBSERIAL/USBSerial.cpp Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -// USBSerial.c -// USB device example: virtual serial port -// Copyright (c) 2011 ARM Limited. All rights reserved - -#include "stdint.h" -#include "USBSerial.h" -#include "USBBusInterface.h" - - -int USBSerial::_putc(int c) { - send(EPBULK_IN, (uint8_t *)&c, 1); - return 1; -} - -int USBSerial::_getc() { - uint8_t c; - while (buf.isEmpty()); - buf.dequeue(&c); - return c; -} - -void USBSerial::attach(void (*ptr)(void)) { - handler = true; - proc = true; - fn = ptr; -} - - -bool USBSerial::EP2_OUT_callback() { - uint8_t c[65]; - uint16_t size = 0; - - //we read the packet received and put it on the circular buffer - USBCDC::read(EPBULK_OUT, c, &size, MAX_PACKET_SIZE_EPBULK); - for (int i = 0; i < size; i++) { - buf.queue(c[i]); - } - - //call a potential handler - if (handler) { - if (proc) { - (*fn)(); - } else { - rx.call(); - } - } - - // We reactivate the endpoint to receive next characters - readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); - return true; -} - -uint8_t USBSerial::available() { - return buf.available(); -}
--- a/USBDevice/USBSERIAL/USBSerial.h Mon Nov 14 10:00:07 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* USBSerial.h */ -/* USB device example: virtual serial port */ -/* Copyright (c) 2011 ARM Limited. All rights reserved. */ - -#ifndef USBSERIAL_H -#define USBSERIAL_H - -#include "USBCDC.h" -#include "Stream.h" -#include "CBuffer.h" - - -/** -* USBSerial example -* -* @code -* #include "mbed.h" -* #include "USBSerial.h" -* -* //Virtual serial port over USB -* USBSerial serial; -* -* int main(void) { -* -* while(1) -* { -* serial.printf("I am a virtual serial port\n"); -* wait(1); -* } -* } -* @endcode -*/ -class USBSerial: public USBCDC, public Stream { -public: - - /** - * Constructor - * - * @param vendor_id Your vendor_id (default: 0x1f00) - * @param product_id Your product_id (default: 0x2012) - * @param product_release Your preoduct_release (default: 0x0001) - * - */ - USBSerial(uint16_t vendor_id = 0x1f00, uint16_t product_id = 0x2012, uint16_t product_release = 0x0001): USBCDC(vendor_id, product_id, product_release){ - handler = false; - proc = false; - }; - - - /** - * Send a character. You can use puts, printf. - * - * @param c character to be sent - * @returns true if there is no error, false otherwise - */ - virtual int _putc(int c); - - /** - * Read a character: blocking - * - * @returns character read - */ - virtual int _getc(); - - /** - * Check the number of bytes available. - * - * @returns the number of bytes available - */ - uint8_t available(); - - /** - * Attach a member function to call when a packet is received. - * - * @param tptr pointer to the object to call the member function on - * @param mptr pointer to the member function to be called - */ - template<typename T> - void attach(T* tptr, void (T::*mptr)(void)) { - if((mptr != NULL) && (tptr != NULL)) { - proc = false; - handler = true; - rx.attach(tptr, mptr); - } - } - - /** - * Attach a callback for when a packet is received - * - * @param fptr function pointer - */ - void attach(void (*fn)(void)); - - -protected: - virtual bool EP2_OUT_callback(); - -private: - FunctionPointer rx; - CBuffer buf; - void (*fn)(void); - bool handler; - bool proc; -}; - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD/USBMSD.cpp Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,614 @@ +// USBMSD.cpp +// USB mass storage device example +// Copyright (c) 2011 ARM Limited. All rights reserved. + +#include "stdint.h" +#include "USBMSD.h" +#include "USBBusInterface.h" + +#define CBW_Signature 0x43425355 +#define CSW_Signature 0x53425355 + +// SCSI Commands +#define TEST_UNIT_READY 0x00 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define INQUIRY 0x12 +#define MODE_SELECT6 0x15 +#define MODE_SENSE6 0x1A +#define START_STOP_UNIT 0x1B +#define MEDIA_REMOVAL 0x1E +#define READ_FORMAT_CAPACITIES 0x23 +#define READ_CAPACITY 0x25 +#define READ10 0x28 +#define WRITE10 0x2A +#define VERIFY10 0x2F +#define READ12 0xA8 +#define WRITE12 0xAA +#define MODE_SELECT10 0x55 +#define MODE_SENSE10 0x5A + +// MSC class specific requests +#define MSC_REQUEST_RESET 0xFF +#define MSC_REQUEST_GET_MAX_LUN 0xFE + +#define DEFAULT_CONFIGURATION (1) + +// Max In/Out Packet Size on the bulk endpoint */ +#define MAX_PACKET MAX_PACKET_SIZE_EPBULK + +// CSW Status +enum Status { + CSW_PASSED, + CSW_FAILED, + CSW_ERROR, +}; + + +USBMSD::USBMSD(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) { +} + + +DigitalOut l2(LED2); +// Called in ISR context to process a class specific request +bool USBMSD::USBCallback_request(void) { + + bool success = false; + CONTROL_TRANSFER * transfer = getTransferPtr(); + + if (transfer->setup.bmRequestType.Type == CLASS_TYPE) { + switch (transfer->setup.bRequest) { + case MSC_REQUEST_RESET: + reset(); + success = true; + break; + case MSC_REQUEST_GET_MAX_LUN: + transfer->remaining = 1; + transfer->ptr = getMaxLUN(); + transfer->direction = DEVICE_TO_HOST; + success = true; + break; + default: + break; + } + } + + return success; +} + + +bool USBMSD::connect() { + + //disk initialization + diskInit(); + + // get block size + BlockSize = blockSize(); + if (BlockSize != 0) { + page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t)); + if (page == NULL) + return false; + } + + //get memory size + MemorySize = memorySize(); + if (!MemorySize) { + return false; + } + BlockCount = MemorySize/BlockSize; + + //connect the device + USBDevice::connect(); + return true; +} + + +void USBMSD::reset() { + stage = READ_CBW; +} + +uint8_t * USBMSD::getMaxLUN() { + static uint8_t LUN[] = {0}; + return LUN; +} + +// Called in ISR context called when a data is received +bool USBMSD::EP2_OUT_callback() { + uint16_t size = 0; + uint8_t buf[MAX_PACKET_SIZE_EPBULK]; + read(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK); + switch (stage) { + // the device has to decode the CBW received + case READ_CBW: + CBWDecode(buf, size); + break; + + // the device has to receive data from the host + case PROCESS_CBW: + switch (cbw.CB[0]) { + case WRITE10: + case WRITE12: + memoryWrite(buf, size); + break; + case VERIFY10: + memoryVerify(buf, size); + break; + } + break; + + // an error has occured: stall endpoint and send CSW + default: + stallEndpoint(EPBULK_OUT); + csw.Status = CSW_ERROR; + sendCSW(); + break; + } + + //reactivate readings on the OUT bulk endpoint + readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + return true; +} + +// Called in ISR context when a data has been transferred +bool USBMSD::EP2_IN_callback() { + switch (stage) { + + // the device has to send data to the host + case PROCESS_CBW: + switch (cbw.CB[0]) { + case READ10: + case READ12: + memoryRead(); + break; + } + break; + + //the device has to send a CSW + case SEND_CSW: + sendCSW(); + break; + + // an error has occured + case ERROR: + stallEndpoint(EPBULK_IN); + sendCSW(); + break; + + // the host has received the CSW -> we wait a CBW + case WAIT_CSW: + stage = READ_CBW; + break; + } + return true; +} + + +void USBMSD::memoryWrite (uint8_t * buf, uint16_t size) { + + if ((addr + size) > MemorySize) { + size = MemorySize - addr; + stage = ERROR; + stallEndpoint(EPBULK_OUT); + } + + // we fill an array in RAM of 1 block before writing it in memory + for (int i = 0; i < size; i++) + page[addr%BlockSize + i] = buf[i]; + + // if the array is filled, write it in memory + if (!((addr + size)%BlockSize)) + blockWrite(page, addr/BlockSize); + + addr += size; + length -= size; + csw.DataResidue -= size; + + if ((!length) || (stage != PROCESS_CBW)) { + csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED; + sendCSW(); + } +} + +void USBMSD::memoryVerify (uint8_t * buf, uint16_t size) { + uint32_t n; + + if ((addr + size) > MemorySize) { + size = MemorySize - addr; + stage = ERROR; + stallEndpoint(EPBULK_OUT); + } + + // beginning of a new block -> load a whole block in RAM + if (!(addr%BlockSize)) + blockRead(page, addr/BlockSize); + + // info are in RAM -> no need to re-read memory + for (n = 0; n < size; n++) { + if (page[addr%BlockSize + n] != buf[n]) { + memOK = false; + break; + } + } + + addr += size; + length -= size; + csw.DataResidue -= size; + + if ( !length || (stage != PROCESS_CBW)) { + csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED; + sendCSW(); + } +} + + +bool USBMSD::inquiryRequest (void) { + uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01, + 36 - 4, 0x80, 0x00, 0x00, + 'M', 'B', 'E', 'D', '.', 'O', 'R', 'G', + 'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ', + '1', '.', '0', ' ', + }; + if (!write(inquiry, sizeof(inquiry))) { + return false; + } + return true; +} + + +bool USBMSD::readFormatCapacity() { + uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08, + (BlockCount >> 24) & 0xff, + (BlockCount >> 16) & 0xff, + (BlockCount >> 8) & 0xff, + (BlockCount >> 0) & 0xff, + + 0x02, + (BlockSize >> 16) & 0xff, + (BlockSize >> 8) & 0xff, + (BlockSize >> 0) & 0xff, + }; + if (!write(capacity, sizeof(capacity))) { + return false; + } + return true; +} + + +bool USBMSD::readCapacity (void) { + uint8_t capacity[] = { + ((BlockCount - 1) >> 24) & 0xff, + ((BlockCount - 1) >> 16) & 0xff, + ((BlockCount - 1) >> 8) & 0xff, + ((BlockCount - 1) >> 0) & 0xff, + + (BlockSize >> 24) & 0xff, + (BlockSize >> 16) & 0xff, + (BlockSize >> 8) & 0xff, + (BlockSize >> 0) & 0xff, + }; + if (!write(capacity, sizeof(capacity))) { + return false; + } + return true; +} + +bool USBMSD::write (uint8_t * buf, uint16_t size) { + + if (size >= cbw.DataLength) { + size = cbw.DataLength; + } + stage = SEND_CSW; + + if (!writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) { + return false; + } + + csw.DataResidue -= size; + csw.Status = CSW_PASSED; + return true; +} + + +bool USBMSD::modeSense6 (void) { + uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 }; + if (!write(sense6, sizeof(sense6))) { + return false; + } + return true; +} + +void USBMSD::sendCSW() { + csw.Signature = CSW_Signature; + writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK); + stage = WAIT_CSW; +} + +bool USBMSD::requestSense (void) { + uint8_t request_sense[] = { + 0x70, // Response Code + 0x00, + 0x05, // Sense Key: illegal request + 0x00, + 0x00, + 0x00, + 0x00, + 0x0A, // Additional Length + 0x00, + 0x00, + 0x00, + 0x00, + 0x30, // ASC + 0x01, // ASCQ + 0x00, + 0x00, + 0x00, + 0x00, + }; + + if (!write(request_sense, sizeof(request_sense))) { + return false; + } + + return true; +} + +void USBMSD::fail() { + csw.Status = CSW_FAILED; + sendCSW(); +} + +DigitalOut l1(LED1); +void USBMSD::CBWDecode(uint8_t * buf, uint16_t size) { + if (size == sizeof(cbw)) { + memcpy((uint8_t *)&cbw, buf, size); + if (cbw.Signature == CBW_Signature) { + csw.Tag = cbw.Tag; + csw.DataResidue = cbw.DataLength; + if ((cbw.CBLength < 1) || (cbw.CBLength > 16) ) { + fail(); + } else { + switch (cbw.CB[0]) { + case TEST_UNIT_READY: + testUnitReady(); + break; + case REQUEST_SENSE: + requestSense(); + break; + case INQUIRY: + inquiryRequest(); + break; + case MODE_SENSE6: + modeSense6(); + break; + case READ_FORMAT_CAPACITIES: + readFormatCapacity(); + break; + case READ_CAPACITY: + readCapacity(); + break; + case READ10: + case READ12: + if (infoTransfer()) { + if ((cbw.Flags & 0x80)) { + stage = PROCESS_CBW; + memoryRead(); + } else { + stallEndpoint(EPBULK_OUT); + csw.Status = CSW_ERROR; + sendCSW(); + } + } + break; + case WRITE10: + case WRITE12: + if (infoTransfer()) { + if (!(cbw.Flags & 0x80)) { + stage = PROCESS_CBW; + } else { + stallEndpoint(EPBULK_IN); + csw.Status = CSW_ERROR; + sendCSW(); + } + } + break; + case VERIFY10: + if (!(cbw.CB[1] & 0x02)) { + csw.Status = CSW_PASSED; + sendCSW(); + break; + } + if (infoTransfer()) { + if (!(cbw.Flags & 0x80)) { + stage = PROCESS_CBW; + memOK = true; + } else { + stallEndpoint(EPBULK_IN); + csw.Status = CSW_ERROR; + sendCSW(); + } + } + break; + default: + fail(); + break; + } + } + } + } +} + +void USBMSD::testUnitReady (void) { + + if (cbw.DataLength != 0) { + if ((cbw.Flags & 0x80) != 0) { + stallEndpoint(EPBULK_IN); + } else { + stallEndpoint(EPBULK_OUT); + } + } + + csw.Status = CSW_PASSED; + sendCSW(); +} + + +void USBMSD::memoryRead (void) { + uint32_t n; + + n = (length > MAX_PACKET) ? MAX_PACKET : length; + + if ((addr + n) > MemorySize) { + n = MemorySize - addr; + stage = ERROR; + } + + // we read an entire block + if (!(addr%BlockSize)) + blockRead(page, addr/BlockSize); + + // write data which are in RAM + writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK); + + addr += n; + length -= n; + + csw.DataResidue -= n; + + if ( !length || (stage != PROCESS_CBW)) { + csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED; + sendCSW(); + } +} + + +bool USBMSD::infoTransfer (void) { + uint32_t n; + + // Logical Block Address of First Block + n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] << 8) | (cbw.CB[5] << 0); + + addr = n * BlockSize; + + // Number of Blocks to transfer + switch (cbw.CB[0]) { + case READ10: + case WRITE10: + case VERIFY10: + n = (cbw.CB[7] << 8) | (cbw.CB[8] << 0); + break; + + case READ12: + case WRITE12: + n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] << 8) | (cbw.CB[9] << 0); + break; + } + + length = n * BlockSize; + + if (!cbw.DataLength) { // host requests no data + csw.Status = CSW_FAILED; + sendCSW(); + return false; + } + + if (cbw.DataLength != length) { + if ((cbw.Flags & 0x80) != 0) { + stallEndpoint(EPBULK_IN); + } else { + stallEndpoint(EPBULK_OUT); + } + + csw.Status = CSW_FAILED; + sendCSW(); + return false; + } + + return true; +} + + + + + +// Called in ISR context +// Set configuration. Return false if the +// configuration is not supported. +bool USBMSD::USBCallback_setConfiguration(uint8_t configuration) { + if (configuration != DEFAULT_CONFIGURATION) { + return false; + } + + // Configure endpoints > 0 + addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK); + addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + + //activate readings + readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK); + return true; +} + + +uint8_t * USBMSD::stringIinterfaceDesc() { + static uint8_t stringIinterfaceDescriptor[] = { + 0x08, //bLength + STRING_DESCRIPTOR, //bDescriptorType 0x03 + 'M',0,'S',0,'D',0 //bString iInterface - MSD + }; + return stringIinterfaceDescriptor; +} + +uint8_t * USBMSD::stringIproductDesc() { + static uint8_t stringIproductDescriptor[] = { + 0x12, //bLength + STRING_DESCRIPTOR, //bDescriptorType 0x03 + 'M',0,'b',0,'e',0,'d',0,' ',0,'M',0,'S',0,'D',0 //bString iProduct - Mbed Audio + }; + return stringIproductDescriptor; +} + + +uint8_t * USBMSD::configurationDesc() { + static uint8_t configDescriptor[] = { + + // Configuration 1 + 9, // bLength + 2, // bDescriptorType + LSB(9 + 9 + 7 + 7), // wTotalLength + MSB(9 + 9 + 7 + 7), + 0x01, // bNumInterfaces + 0x01, // bConfigurationValue: 0x01 is used to select this configuration + 0x00, // iConfiguration: no string to describe this configuration + 0xC0, // bmAttributes + 100, // bMaxPower, device power consumption is 100 mA + + // Interface 0, Alternate Setting 0, MSC Class + 9, // bLength + 4, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0x08, // bInterfaceClass + 0x06, // bInterfaceSubClass + 0x50, // bInterfaceProtocol + 0x04, // iInterface + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + PHY_TO_DESC(EPBULK_IN), // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0, // bInterval + + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + PHY_TO_DESC(EPBULK_OUT), // bEndpointAddress + 0x02, // bmAttributes (0x02=bulk) + LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB) + 0 // bInterval + }; + return configDescriptor; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD/USBMSD.h Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,204 @@ +/* USBMSD.h */ +/* USB mass storage device example */ +/* Copyright (c) 2011 ARM Limited. All rights reserved. */ + +/* +* Guide to adapt this class to your storage chip: +* +*/ + +#ifndef USBMSD_H +#define USBMSD_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) + + +// MSC Bulk-only Stage +enum Stage { + READ_CBW, // wait a CBW + ERROR, // error + PROCESS_CBW, // process a CBW request + SEND_CSW, // send a CSW + WAIT_CSW, // wait that a CSW has been effectively sent +}; + +// Bulk-only CBW +typedef __packed struct { + uint32_t Signature; + uint32_t Tag; + uint32_t DataLength; + uint8_t Flags; + uint8_t LUN; + uint8_t CBLength; + uint8_t CB[16]; +} CBW; + +// Bulk-only CSW +typedef __packed struct { + uint32_t Signature; + uint32_t Tag; + uint32_t DataResidue; + uint8_t Status; +} CSW; + + +class USBMSD: public USBDevice { +public: + + /** + * Constructor + * + * @param vendor_id Your vendor_id + * @param product_id Your product_id + * @param product_release Your preoduct_release + */ + USBMSD(uint16_t vendor_id = 0x0703, uint16_t product_id = 0x0104, uint16_t product_release = 0x0001); + + /* + * read a block on a storage chip + * + * @param data pointer where will be stored read data + * @param block block number + * @returns 0 if successful + */ + virtual int blockRead(uint8_t * data, uint16_t block){return 1;}; + + /* + * write a block on a storage chip + * + * @param data data to write + * @param block block number + * @returns 0 if successful + */ + virtual int blockWrite(uint8_t * data, uint16_t block){return 1;}; + + /* + * Disk initilization + */ + virtual int diskInit(){return -1;}; + + /* + * Return block size + * + * @returns size of a block + */ + virtual uint16_t blockSize(){return 0;}; + + /* + * Return memory size + * + * @returns memory size + */ + virtual uint32_t memorySize(){return 0;}; + + /* + * Connect the USB MSD device. Establish disk initialization before really connect the device. + * + * @returns + */ + bool connect(); + + +protected: + + + /* + * Get number of logical unit - 1 (here 0) + * + * @returns Pointer containing the number of logical unit - 1 + */ + uint8_t * getMaxLUN(); + + /* + * 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(); + + /* + * Callback called when a packet is received + */ + virtual bool EP2_OUT_callback(); + + /* + * Callback called when a packet has been sent + */ + virtual bool EP2_IN_callback(); + + /* + * Set configuration of device. Add endpoints + */ + virtual bool USBCallback_setConfiguration(uint8_t configuration); + + /* + * Callback called to process class specific requests + */ + virtual bool USBCallback_request(); + + +private: + //state of the bulk-only state machine + Stage stage; + + // current CBW + CBW cbw; + + // CSW which will be sent + CSW csw; + + // addr where will be read or written data + uint32_t addr; + + // length of a reading or writing + uint32_t length; + + // memory OK (after a memoryVerify) + bool memOK; + + // cache in RAM before writing in memory. Useful also to read a block. + uint8_t * page; + + uint16_t BlockSize; + uint32_t MemorySize; + uint16_t BlockCount; + + void CBWDecode(uint8_t * buf, uint16_t size); + void sendCSW (void); + bool inquiryRequest (void); + bool write (uint8_t * buf, uint16_t size); + bool readFormatCapacity(); + bool readCapacity (void); + bool infoTransfer (void); + void memoryRead (void); + bool modeSense6 (void); + void testUnitReady (void); + bool requestSense (void); + void memoryVerify (uint8_t * buf, uint16_t size); + void memoryWrite (uint8_t * buf, uint16_t size); + void reset(); + void fail(); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD/USB_SDcard.cpp Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,374 @@ +/* mbed USB_SDcard Library, for accessing 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. + */ + +#include "USB_SDcard.h" + +#define SD_COMMAND_TIMEOUT 5000 + +USB_SDcard::USB_SDcard(PinName mosi, PinName miso, PinName sclk, PinName cs): + _spi(mosi, miso, sclk), _cs(cs) { + _cs = 1; + USBMSD::connect(); +} + +#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 USB_SDcard::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 USB_SDcard::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 USB_SDcard::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; +} + +uint32_t USB_SDcard::memorySize() +{ + return (uint32_t)capacity; +} + +uint16_t USB_SDcard::blockSize() +{ + return (uint16_t)block_len; +} + +int USB_SDcard::diskInit() { + + 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 USB_SDcard::blockWrite(uint8_t * buffer, uint16_t block_number) { + // set write address for single block (CMD24) + if(_cmd(24, block_number * 512) != 0) { + return 1; + } + + // send the data block + _write((const char *)buffer, 512); + return 0; +} + +int USB_SDcard::blockRead(uint8_t * buffer, uint16_t block_number) { + // set read address for single block (CMD17) + if(_cmd(17, block_number * 512) != 0) { + return 1; + } + + // receive the data + _read((char *)buffer, 512); + return 0; +} + +int USB_SDcard::disk_status() { return 0; } +int USB_SDcard::disk_sync() { return 0; } +int USB_SDcard::disk_sectors() { return _sectors; } + +// PRIVATE FUNCTIONS + +int USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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 USB_SDcard::_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) + + block_len = 1 << read_bl_len; + int mult = 1 << (c_size_mult + 2); + int blocknr = (c_size + 1) * mult; + capacity = blocknr * block_len; + + int blocks = capacity / 512; + + return blocks; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBMSD/USB_SDcard.h Mon Nov 14 12:08:32 2011 +0000 @@ -0,0 +1,87 @@ +/* mbed USB_SDcard Library, for accessing 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 USB_SDCARD_H +#define USB_SDCARD_H + +#include "mbed.h" +#include "USBMSD.h" + +class USB_SDcard : public USBMSD { +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 + */ + USB_SDcard(PinName mosi = p5, PinName miso = p6, PinName sclk = p7, PinName cs = p8); + + /* + * read a block on a storage chip + * + * @param data pointer where will be stored read data + * @param block block number + * @returns 0 if successful + */ + virtual int blockRead(uint8_t * data, uint16_t block); + + /* + * write a block on a storage chip + * + * @param data data to write + * @param block block number + * @returns 0 if successful + */ + virtual int blockWrite(uint8_t * data, uint16_t block); + + virtual int diskInit(); + virtual uint16_t blockSize(); + virtual uint32_t memorySize(); + +protected: + + int disk_status(); + int disk_sync(); + int disk_sectors(); + 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; + int capacity; + int block_len; + + SPI _spi; + DigitalOut _cs; +}; + +#endif
--- a/main.cpp Mon Nov 14 10:00:07 2011 +0000 +++ b/main.cpp Mon Nov 14 12:08:32 2011 +0000 @@ -1,8 +1,19 @@ #include "mbed.h" #include "USB_SDcard.h" +#include "SDFileSystem.h" USB_SDcard sd; +SDFileSystem sd1(p5, p6, p7, p8, "sd"); int main() { + mkdir("/sd/mydir", 0777); + + FILE *fp = fopen("/sd/mydir/sdtest.txt", "w"); + if(fp == NULL) { + error("Could not open file for write\n"); + } + fprintf(fp, "Hello fun SD Card World!"); + fclose(fp); + while(1); }