diff --git a/.github/makecode/blocks.png b/.github/makecode/blocks.png deleted file mode 100644 index ff01e32..0000000 Binary files a/.github/makecode/blocks.png and /dev/null differ diff --git a/.github/workflows/makecode.yml b/.github/workflows/makecode.yml deleted file mode 100644 index 1aa354c..0000000 --- a/.github/workflows/makecode.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: MakeCode - -on: [push] - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [8.x] - - steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: npm install - run: | - npm install -g pxt - pxt target microbit - - name: build - run: | - pxt install - pxt build --cloud - env: - CI: true diff --git a/.github/workflows/maker.yml b/.github/workflows/maker.yml new file mode 100644 index 0000000..316cc1d --- /dev/null +++ b/.github/workflows/maker.yml @@ -0,0 +1,44 @@ +name: maker + +on: + push: + branches: + - master + schedule: + - cron: '0 0 5,20 * *' + +jobs: + prepare: + runs-on: ubuntu-latest + if: "! contains(github.event.head_commit.message, '[skip ci]')" + steps: + - run: echo "${{ github.event.head_commit.message }}" + + build: + needs: prepare + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [8.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: maker pxt.json + uses: datamonsters/replace-action@master + with: + files: 'pxt.json' + replacements: 'core=xinabox-cs11,test.ts=dummy.ts' + - name: maker compilation + run: | + npm install -g pxt + pxt target maker + pxt install + pxt build --cloud + env: + CI: true diff --git a/.gitignore b/.gitignore index d2196e7..26c0c1f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -# MakeCode built node_modules yotta_modules @@ -8,4 +7,9 @@ _site *.db *.tgz .header.json -.simstate.json +main.ts +main.blocks +Gemfile +_config.yml +tsconfig.json +.vscode \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f8106d4..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "editor.formatOnType": true, - "files.autoSave": "afterDelay", - "files.watcherExclude": { - "**/.git/objects/**": true, - "**/built/**": true, - "**/node_modules/**": true, - "**/yotta_modules/**": true, - "**/yotta_targets": true, - "**/pxt_modules/**": true - }, - "files.associations": { - "*.blocks": "html", - "*.jres": "json" - }, - "search.exclude": { - "**/built": true, - "**/node_modules": true, - "**/yotta_modules": true, - "**/yotta_targets": true, - "**/pxt_modules": true - } -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 9ee2cf6..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,30 +0,0 @@ - -// A task runner that calls the MakeCode (PXT) compiler -{ - "version": "2.0.0", - "tasks": [{ - "label": "pxt deploy", - "type": "shell", - "command": "pxt deploy --local", - "group": "build", - "problemMatcher": [ "$tsc" ] - }, { - "label": "pxt build", - "type": "shell", - "command": "pxt build --local", - "group": "build", - "problemMatcher": [ "$tsc" ] - }, { - "label": "pxt install", - "type": "shell", - "command": "pxt install", - "group": "build", - "problemMatcher": [ "$tsc" ] - }, { - "label": "pxt clean", - "type": "shell", - "command": "pxt clean", - "group": "test", - "problemMatcher": [ "$tsc" ] - }] -} diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 91ceacd..0000000 --- a/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source 'https://rubygems.org' -gem 'github-pages', group: :jekyll_plugins \ No newline at end of file diff --git a/README.md b/README.md index 6246e5c..3728537 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,36 @@ +[![GitHub Issues](https://img.shields.io/github/issues/xinabox/pxt-CS11.svg)](https://github.com/xinabox/pxt-CS11/issues) +![GitHub Commit](https://img.shields.io/github/last-commit/xinabox/pxt-CS11) +![Maintained](https://img.shields.io/maintenance/yes/2020) +![Build status badge](https://github.com/xinabox/pxt-CS11/workflows/maker/badge.svg) +![Developer](https://img.shields.io/badge/Developer-lb-blue) -> Open this page at [https://xinabox.github.io/pxt-im01-2/](https://xinabox.github.io/pxt-im01-2/) +> Open this page at [https://.github.io//](https://.github.io//) ## Use as Extension This repository can be added as an **extension** in MakeCode. -* open [https://makecode.microbit.org/](https://makecode.microbit.org/) +* open []() * click on **New Project** * click on **Extensions** under the gearwheel menu -* search for **https://github.com/xinabox/pxt-im01-2** and import +* search for **https://github.com/** and import -## Edit this project ![Build status badge](https://github.com/xinabox/pxt-im01-2/workflows/MakeCode/badge.svg) +## Edit this project ![Build status badge](https://github.com//workflows/MakeCode/badge.svg) To edit this repository in MakeCode. -* open [https://makecode.microbit.org/](https://makecode.microbit.org/) +* open []() * click on **Import** then click on **Import URL** -* paste **https://github.com/xinabox/pxt-im01-2** and click import +* paste **https://github.com/** and click import ## Blocks preview This image shows the blocks code from the last commit in master. This image may take a few minutes to refresh. -![A rendered view of the blocks](https://github.com/xinabox/pxt-im01-2/raw/master/.github/makecode/blocks.png) +![A rendered view of the blocks](https://github.com//raw/master/.github/makecode/blocks.png) #### Metadata (used for search, rendering) -* for PXT/microbit +* for PXT/ diff --git a/_config.yml b/_config.yml deleted file mode 100644 index f56a029..0000000 --- a/_config.yml +++ /dev/null @@ -1,8 +0,0 @@ -makecode: - target: microbit - platform: microbit - home_url: https://makecode.microbit.org/ -theme: jekyll-theme-slate -include: - - assets - - README.md diff --git a/diskio.h b/diskio.h new file mode 100644 index 0000000..f3b3b5e --- /dev/null +++ b/diskio.h @@ -0,0 +1,38 @@ +#include "ff.h" +#ifndef _DISKIO_DEFINED +#define _DISKIO_DEFINED + +typedef BYTE DSTATUS; + +typedef enum +{ + RES_OK = 0, + RES_ERROR, + RES_WRPRT, + RES_NOTRDY, + RES_PARERR +} DRESULT; + +DSTATUS disk_initialize(BYTE pdrv); +DSTATUS disk_status(BYTE pdrv); +DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count); +DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count); +DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff); + +#define STA_NOINIT 0x01 + +#define STA_PROTECT 0x04 + +#define CTRL_SYNC 0 +#define GET_SECTOR_COUNT 1 +#define GET_SECTOR_SIZE 2 +#define GET_BLOCK_SIZE 3 +#define CTRL_TRIM 4 + +#define CT_MMC 0x01 +#define CT_SD1 0x02 +#define CT_SD2 0x04 +#define CT_SDC (CT_SD1 | CT_SD2) +#define CT_BLOCK 0x08 + +#endif diff --git a/dummy.ts b/dummy.ts new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/dummy.ts @@ -0,0 +1 @@ + diff --git a/ff.cpp b/ff.cpp new file mode 100644 index 0000000..3bb63a4 --- /dev/null +++ b/ff.cpp @@ -0,0 +1,1783 @@ +#include "ff.h" +#include "diskio.h" + +#define MAX_DIR 0x200000 +#define MAX_DIR_EX 0x10000000 +#define MAX_FAT12 0xFF5 +#define MAX_FAT16 0xFFF5 +#define MAX_FAT32 0x0FFFFFF5 + +#define IsLower(c) ((c) >= 'a' && (c) <= 'z') +#define IsDigit(c) ((c) >= '0' && (c) <= '9') + +#define FA_SEEKEND 0x20 +#define FA_MODIFIED 0x40 + +#define AM_VOL 0x08 +#define AM_LFN 0x0F +#define AM_MASK 0x3F + +#define NSFLAG 11 + +#define NS_LAST 0x04 + +#define NS_DOT 0x20 + +#define NS_NONAME 0x80 + +#define BS_JmpBoot 0 + +#define BPB_BytsPerSec 11 +#define BPB_SecPerClus 13 +#define BPB_RsvdSecCnt 14 +#define BPB_NumFATs 16 +#define BPB_RootEntCnt 17 +#define BPB_TotSec16 19 + +#define BPB_FATSz16 22 + +#define BPB_TotSec32 32 + +#define BS_FilSysType 54 + +#define BS_55AA 510 + +#define BPB_FATSz32 36 + +#define BPB_FSVer32 42 +#define BPB_RootClus32 44 +#define BPB_FSInfo32 48 + +#define BS_FilSysType32 82 + +#define DIR_Name 0 +#define DIR_Attr 11 + +#define DIR_CrtTime 14 +#define DIR_LstAccDate 18 +#define DIR_FstClusHI 20 +#define DIR_ModTime 22 +#define DIR_FstClusLO 26 +#define DIR_FileSize 28 + +#define SZDIRE 32 +#define DDEM 0xE5 +#define RDDEM 0x05 + +#define FSI_LeadSig 0 +#define FSI_StrucSig 484 +#define FSI_Free_Count 488 +#define FSI_Nxt_Free 492 + +#define MBR_Table 446 +#define SZ_PTE 16 + +#define PTE_StLba 8 + +#define ABORT(fs, res) \ + { \ + fp->err = (BYTE)(res); \ + LEAVE_FF(fs, res); \ + } + +#define LEAVE_FF(fs, res) return res + +#define LD2PD(vol) (BYTE)(vol) +#define LD2PT(vol) 0 + +#define SS(fs) ((UINT)FF_MAX_SS) + +#define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16) + +#define TBL_DC932 \ + { \ + 0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00 \ + } + +#define MERGE_2STR(a, b) a##b +#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) + +static FATFS *FatFs[FF_VOLUMES]; +static WORD Fsid; + +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() + +static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); + +static WORD ld_word(const BYTE *ptr) +{ + WORD rv; + + rv = ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +static DWORD ld_dword(const BYTE *ptr) +{ + DWORD rv; + + rv = ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +#if !FF_FS_READONLY +static void st_word(BYTE *ptr, WORD val) +{ + *ptr++ = (BYTE)val; + val >>= 8; + *ptr++ = (BYTE)val; +} + +static void st_dword(BYTE *ptr, DWORD val) +{ + *ptr++ = (BYTE)val; + val >>= 8; + *ptr++ = (BYTE)val; + val >>= 8; + *ptr++ = (BYTE)val; + val >>= 8; + *ptr++ = (BYTE)val; +} + +#endif + +static void mem_cpy(void *dst, const void *src, UINT cnt) +{ + BYTE *d = (BYTE *)dst; + const BYTE *s = (const BYTE *)src; + + if (cnt != 0) + { + do + { + *d++ = *s++; + } while (--cnt); + } +} + +static void mem_set(void *dst, int val, UINT cnt) +{ + BYTE *d = (BYTE *)dst; + + do + { + *d++ = (BYTE)val; + } while (--cnt); +} + +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; + + do + { + r = *d++ - *s++; + } while (--cnt && r == 0); + + return r; +} + +static int chk_chr(const char *str, int chr) +{ + while (*str && *str != chr) + str++; + return *str; +} + +static int dbc_1st(BYTE c) +{ + if (c >= DbcTbl[0]) + { + if (c <= DbcTbl[1]) + return 1; + if (c >= DbcTbl[2] && c <= DbcTbl[3]) + return 1; + } + return 0; +} + +static int dbc_2nd(BYTE c) +{ + if (c >= DbcTbl[4]) + { + if (c <= DbcTbl[5]) + return 1; + if (c >= DbcTbl[6] && c <= DbcTbl[7]) + return 1; + if (c >= DbcTbl[8] && c <= DbcTbl[9]) + return 1; + } + return 0; +} + +#if !FF_FS_READONLY +static FRESULT sync_window( + FATFS *fs) +{ + FRESULT res = FR_OK; + + if (fs->wflag) + { + if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) + { + fs->wflag = 0; + if (fs->winsect - fs->fatbase < fs->fsize) + { + if (fs->n_fats == 2) + disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); + } + } + else + { + res = FR_DISK_ERR; + } + } + return res; +} +#endif + +static FRESULT move_window( + FATFS *fs, + LBA_t sect) +{ + FRESULT res = FR_OK; + + if (sect != fs->winsect) + { +#if !FF_FS_READONLY + res = sync_window(fs); +#endif + if (res == FR_OK) + { + if (disk_read(fs->pdrv, fs->win, sect, 1) != RES_OK) + { + sect = (LBA_t)0 - 1; + res = FR_DISK_ERR; + } + fs->winsect = sect; + } + } + return res; +} + +#if !FF_FS_READONLY + +static FRESULT sync_fs( + FATFS *fs) +{ + FRESULT res; + + res = sync_window(fs); + if (res == FR_OK) + { + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) + { + + mem_set(fs->win, 0, sizeof fs->win); + 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_clst); + st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); + + fs->winsect = fs->volbase + 1; + disk_write(fs->pdrv, fs->win, fs->winsect, 1); + fs->fsi_flag = 0; + } + + if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) + res = FR_DISK_ERR; + } + + return res; +} + +#endif + +static LBA_t clst2sect( + FATFS *fs, + DWORD clst) +{ + clst -= 2; + if (clst >= fs->n_fatent - 2) + return 0; + return fs->database + (LBA_t)fs->csize * clst; +} + +static DWORD get_fat( + FFOBJID *obj, + DWORD clst) +{ + UINT wc, bc; + DWORD val; + FATFS *fs = obj->fs; + + if (clst < 2 || clst >= fs->n_fatent) + { + val = 1; + } + else + { + val = 0xFFFFFFFF; + + switch (fs->fs_type) + { + case FS_FAT32: + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) + break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; + break; + default: + val = 1; + } + } + + return val; +} + +#if !FF_FS_READONLY + +static FRESULT put_fat( + FATFS *fs, + DWORD clst, + DWORD val) +{ + UINT bc; + BYTE *p; + FRESULT res = FR_INT_ERR; + + if (clst >= 2 && clst < fs->n_fatent) + { + switch (fs->fs_type) + { + case FS_FAT32: + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); + if (res != FR_OK) + break; + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) + { + val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); + } + st_dword(fs->win + clst * 4 % SS(fs), val); + fs->wflag = 1; + break; + } + } + return res; +} + +#endif + +#if !FF_FS_READONLY + +static FRESULT remove_chain( + FFOBJID *obj, + DWORD clst, + DWORD pclst) +{ + FRESULT res = FR_OK; + DWORD nxt; + FATFS *fs = obj->fs; + + if (clst < 2 || clst >= fs->n_fatent) + return FR_INT_ERR; + + if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) + { + res = put_fat(fs, pclst, 0xFFFFFFFF); + if (res != FR_OK) + return res; + } + + do + { + nxt = get_fat(obj, clst); + if (nxt == 0) + break; + if (nxt == 1) + return FR_INT_ERR; + if (nxt == 0xFFFFFFFF) + return FR_DISK_ERR; + if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) + { + res = put_fat(fs, clst, 0); + if (res != FR_OK) + return res; + } + if (fs->free_clst < fs->n_fatent - 2) + { + fs->free_clst++; + fs->fsi_flag |= 1; + } + clst = nxt; + } while (clst < fs->n_fatent); + return FR_OK; +} + +static DWORD create_chain( + FFOBJID *obj, + DWORD clst) +{ + DWORD cs, ncl, scl; + FRESULT res; + FATFS *fs = obj->fs; + + if (clst == 0) + { + scl = fs->last_clst; + if (scl == 0 || scl >= fs->n_fatent) + scl = 1; + } + else + { + cs = get_fat(obj, clst); + if (cs < 2) + return 1; + if (cs == 0xFFFFFFFF) + return cs; + if (cs < fs->n_fatent) + return cs; + scl = clst; + } + if (fs->free_clst == 0) + return 0; + { + ncl = 0; + if (scl == clst) + { + ncl = scl + 1; + if (ncl >= fs->n_fatent) + ncl = 2; + cs = get_fat(obj, ncl); + if (cs == 1 || cs == 0xFFFFFFFF) + return cs; + if (cs != 0) + { + cs = fs->last_clst; + if (cs >= 2 && cs < fs->n_fatent) + scl = cs; + ncl = 0; + } + } + if (ncl == 0) + { + ncl = scl; + for (;;) + { + ncl++; + if (ncl >= fs->n_fatent) + { + ncl = 2; + if (ncl > scl) + return 0; + } + cs = get_fat(obj, ncl); + if (cs == 0) + break; + if (cs == 1 || cs == 0xFFFFFFFF) + return cs; + if (ncl == scl) + return 0; + } + } + res = put_fat(fs, ncl, 0xFFFFFFFF); + if (res == FR_OK && clst != 0) + { + res = put_fat(fs, clst, ncl); + } + } + + if (res == FR_OK) + { + fs->last_clst = ncl; + if (fs->free_clst <= fs->n_fatent - 2) + fs->free_clst--; + fs->fsi_flag |= 1; + } + else + { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; + } + + return ncl; +} + +#endif + +#if !FF_FS_READONLY +static FRESULT dir_clear( + FATFS *fs, + DWORD clst) +{ + LBA_t sect; + UINT n, szb; + BYTE *ibuf; + + if (sync_window(fs) != FR_OK) + return FR_DISK_ERR; + sect = clst2sect(fs, clst); + fs->winsect = sect; + mem_set(fs->win, 0, sizeof fs->win); + { + ibuf = fs->win; + szb = 1; + for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) + ; + } + return (n == fs->csize) ? FR_OK : FR_DISK_ERR; +} +#endif + +static FRESULT dir_sdi( + DIR *dp, + DWORD ofs) +{ + DWORD csz, clst; + FATFS *fs = dp->obj.fs; + + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) + { + return FR_INT_ERR; + } + dp->dptr = ofs; + clst = dp->obj.sclust; + if (clst == 0 && fs->fs_type >= FS_FAT32) + { + clst = (DWORD)fs->dirbase; + if (FF_FS_EXFAT) + dp->obj.stat = 0; + } + + if (clst == 0) + { + if (ofs / SZDIRE >= fs->n_rootdir) + return FR_INT_ERR; + dp->sect = fs->dirbase; + } + else + { + csz = (DWORD)fs->csize * SS(fs); + while (ofs >= csz) + { + clst = get_fat(&dp->obj, clst); + if (clst == 0xFFFFFFFF) + return FR_DISK_ERR; + if (clst < 2 || clst >= fs->n_fatent) + return FR_INT_ERR; + ofs -= csz; + } + dp->sect = clst2sect(fs, clst); + } + dp->clust = clst; + if (dp->sect == 0) + return FR_INT_ERR; + dp->sect += ofs / SS(fs); + dp->dir = fs->win + (ofs % SS(fs)); + + return FR_OK; +} + +static FRESULT dir_next( + DIR *dp, + int stretch) +{ + DWORD ofs, clst; + FATFS *fs = dp->obj.fs; + + ofs = dp->dptr + SZDIRE; + if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) + dp->sect = 0; + if (dp->sect == 0) + return FR_NO_FILE; + + if (ofs % SS(fs) == 0) + { + dp->sect++; + + if (dp->clust == 0) + { + if (ofs / SZDIRE >= fs->n_rootdir) + { + dp->sect = 0; + return FR_NO_FILE; + } + } + else + { + if ((ofs / SS(fs) & (fs->csize - 1)) == 0) + { + clst = get_fat(&dp->obj, dp->clust); + if (clst <= 1) + return FR_INT_ERR; + if (clst == 0xFFFFFFFF) + return FR_DISK_ERR; + if (clst >= fs->n_fatent) + { + if (!stretch) + { + dp->sect = 0; + return FR_NO_FILE; + } + clst = create_chain(&dp->obj, dp->clust); + if (clst == 0) + return FR_DENIED; + if (clst == 1) + return FR_INT_ERR; + if (clst == 0xFFFFFFFF) + return FR_DISK_ERR; + if (dir_clear(fs, clst) != FR_OK) + return FR_DISK_ERR; + if (FF_FS_EXFAT) + dp->obj.stat |= 4; + } + dp->clust = clst; + dp->sect = clst2sect(fs, clst); + } + } + } + dp->dptr = ofs; + dp->dir = fs->win + ofs % SS(fs); + + return FR_OK; +} + +#if !FF_FS_READONLY + +static FRESULT dir_alloc( + DIR *dp, + UINT nent) +{ + FRESULT res; + UINT n; + FATFS *fs = dp->obj.fs; + + res = dir_sdi(dp, 0); + if (res == FR_OK) + { + n = 0; + do + { + res = move_window(fs, dp->sect); + if (res != FR_OK) + break; + if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) + { + if (++n == nent) + break; + } + else + { + n = 0; + } + res = dir_next(dp, 1); + } while (res == FR_OK); + } + + if (res == FR_NO_FILE) + res = FR_DENIED; + return res; +} + +#endif + +static DWORD ld_clust( + FATFS *fs, + const BYTE *dir) +{ + DWORD cl; + + cl = ld_word(dir + DIR_FstClusLO); + if (fs->fs_type == FS_FAT32) + { + cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; + } + + return cl; +} + +#if !FF_FS_READONLY +static void st_clust( + FATFS *fs, + BYTE *dir, + DWORD cl) +{ + st_word(dir + DIR_FstClusLO, (WORD)cl); + if (fs->fs_type == FS_FAT32) + { + st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); + } +} +#endif + +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT + +#define DIR_READ_FILE(dp) dir_read(dp, 0) +#define DIR_READ_LABEL(dp) dir_read(dp, 1) + +static FRESULT dir_read( + DIR *dp, + int vol) +{ + FRESULT res = FR_NO_FILE; + FATFS *fs = dp->obj.fs; + BYTE attr, b; + + while (dp->sect) + { + res = move_window(fs, dp->sect); + if (res != FR_OK) + break; + b = dp->dir[DIR_Name]; + if (b == 0) + { + res = FR_NO_FILE; + break; + } + { + dp->obj.attr = attr = dp->dir[DIR_Attr] & AM_MASK; + if (b != DDEM && b != '.' && attr != AM_LFN && (int)((attr & ~AM_ARC) == AM_VOL) == vol) + { + break; + } + } + res = dir_next(dp, 0); + if (res != FR_OK) + break; + } + + if (res != FR_OK) + dp->sect = 0; + return res; +} + +#endif + +static FRESULT dir_find( + DIR *dp) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; + BYTE c; + + res = dir_sdi(dp, 0); + if (res != FR_OK) + return res; + do + { + res = move_window(fs, dp->sect); + if (res != FR_OK) + break; + c = dp->dir[DIR_Name]; + if (c == 0) + { + res = FR_NO_FILE; + break; + } + dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; + if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) + break; + res = dir_next(dp, 0); + } while (res == FR_OK); + + return res; +} + +#if !FF_FS_READONLY + +static FRESULT dir_register( + DIR *dp) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; + + res = dir_alloc(dp, 1); + + if (res == FR_OK) + { + res = move_window(fs, dp->sect); + if (res == FR_OK) + { + mem_set(dp->dir, 0, SZDIRE); + mem_cpy(dp->dir + DIR_Name, dp->fn, 11); + fs->wflag = 1; + } + } + + return res; +} + +#endif + +#if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 + +static FRESULT dir_remove( + DIR *dp) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; + + res = move_window(fs, dp->sect); + if (res == FR_OK) + { + dp->dir[DIR_Name] = DDEM; + fs->wflag = 1; + } + + return res; +} + +#endif + +#if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 + +static void get_fileinfo( + DIR *dp, + FILINFO *fno) +{ + UINT si, di; + TCHAR c; + + fno->fname[0] = 0; + if (dp->sect == 0) + return; + + si = di = 0; + while (si < 11) + { + c = (TCHAR)dp->dir[si++]; + if (c == ' ') + continue; + if (c == RDDEM) + c = DDEM; + if (si == 9) + fno->fname[di++] = '.'; + fno->fname[di++] = c; + } + fno->fname[di] = 0; + + fno->fattrib = dp->dir[DIR_Attr]; + fno->fsize = ld_dword(dp->dir + DIR_FileSize); + fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); + fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); +} + +#endif + +static FRESULT create_name( + DIR *dp, + const TCHAR **path) +{ + BYTE c, d, *sfn; + UINT ni, si, i; + const char *p; + + p = *path; + sfn = dp->fn; + mem_set(sfn, ' ', 11); + si = i = 0; + ni = 8; + for (;;) + { + c = (BYTE)p[si++]; + if (c <= ' ') + break; + if (c == '/' || c == '\\') + { + while (p[si] == '/' || p[si] == '\\') + si++; + break; + } + if (c == '.' || i >= ni) + { + if (ni == 11 || c != '.') + return FR_INVALID_NAME; + i = 8; + ni = 11; + continue; + } + if (dbc_1st(c)) + { + d = (BYTE)p[si++]; + if (!dbc_2nd(d) || i >= ni - 1) + return FR_INVALID_NAME; + sfn[i++] = c; + sfn[i++] = d; + } + else + { + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) + return FR_INVALID_NAME; + if (IsLower(c)) + c -= 0x20; + sfn[i++] = c; + } + } + *path = p + si; + if (i == 0) + return FR_INVALID_NAME; + + if (sfn[0] == DDEM) + sfn[0] = RDDEM; + sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; + + return FR_OK; +} + +static FRESULT follow_path( + DIR *dp, + const TCHAR *path) +{ + FRESULT res; + BYTE ns; + FATFS *fs = dp->obj.fs; + { + while (*path == '/' || *path == '\\') + path++; + dp->obj.sclust = 0; + } + + if ((UINT)*path < ' ') + { + dp->fn[NSFLAG] = NS_NONAME; + res = dir_sdi(dp, 0); + } + else + { + for (;;) + { + res = create_name(dp, &path); + if (res != FR_OK) + break; + res = dir_find(dp); + ns = dp->fn[NSFLAG]; + if (res != FR_OK) + { + if (res == FR_NO_FILE) + { + if (FF_FS_RPATH && (ns & NS_DOT)) + { + if (!(ns & NS_LAST)) + continue; + dp->fn[NSFLAG] = NS_NONAME; + res = FR_OK; + } + else + { + if (!(ns & NS_LAST)) + res = FR_NO_PATH; + } + } + break; + } + if (ns & NS_LAST) + break; + + if (!(dp->obj.attr & AM_DIR)) + { + res = FR_NO_PATH; + break; + } + { + dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); + } + } + } + + return res; +} + +static int get_ldnumber( + const TCHAR **path) +{ + const TCHAR *tp, *tt; + TCHAR tc; + int i, vol = -1; + + tt = tp = *path; + if (!tp) + return vol; + do + tc = *tt++; + while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':'); + + if (tc == ':') + { + i = FF_VOLUMES; + if (IsDigit(*tp) && tp + 2 == tt) + { + i = (int)*tp - '0'; + } + if (i < FF_VOLUMES) + { + vol = i; + *path = tt; + } + return vol; + } + vol = 0; + return vol; +} + +static UINT check_fs( + FATFS *fs, + LBA_t sect) +{ + fs->wflag = 0; + fs->winsect = (LBA_t)0 - 1; + if (move_window(fs, sect) != FR_OK) + return 4; + + if (ld_word(fs->win + BS_55AA) != 0xAA55) + return 3; + + if (FF_FS_EXFAT && !mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" + "EXFAT ", + 11)) + return 1; + + if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) + { + if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3)) + return 0; + if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5)) + return 0; + } + return 2; +} + +static UINT find_volume( + FATFS *fs, + UINT part) +{ + UINT fmt, i; + DWORD mbr_pt[4]; + + fmt = check_fs(fs, 0); + if (fmt != 2 && (fmt >= 3 || part == 0)) + return fmt; + + if (FF_MULTI_PARTITION && part > 4) + return 3; + for (i = 0; i < 4; i++) + { + mbr_pt[i] = ld_dword(fs->win + MBR_Table + i * SZ_PTE + PTE_StLba); + } + i = part ? part - 1 : 0; + do + { + fmt = mbr_pt[i] ? check_fs(fs, mbr_pt[i]) : 3; + } while (part == 0 && fmt >= 2 && ++i < 4); + return fmt; +} + +static FRESULT mount_volume( + const TCHAR **path, + FATFS **rfs, + BYTE mode) +{ + int vol; + DSTATUS stat; + LBA_t bsect; + DWORD tsect, sysect, fasize, nclst, szbfat; + WORD nrsv; + FATFS *fs; + UINT fmt; + + *rfs = 0; + vol = get_ldnumber(path); + if (vol < 0) + return FR_INVALID_DRIVE; + + fs = FatFs[vol]; + if (!fs) + return FR_NOT_ENABLED; + *rfs = fs; + + mode &= (BYTE)~FA_READ; + if (fs->fs_type != 0) + { + stat = disk_status(fs->pdrv); + if (!(stat & STA_NOINIT)) + { + if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) + { + return FR_WRITE_PROTECTED; + } + return FR_OK; + } + } + + fs->fs_type = 0; + fs->pdrv = LD2PD(vol); + stat = disk_initialize(fs->pdrv); + if (stat & STA_NOINIT) + { + return FR_NOT_READY; + } + if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) + { + return FR_WRITE_PROTECTED; + } + + fmt = find_volume(fs, LD2PT(vol)); + if (fmt == 4) + return FR_DISK_ERR; + if (fmt >= 2) + return FR_NO_FILESYSTEM; + bsect = fs->winsect; + { + if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) + return FR_NO_FILESYSTEM; + + fasize = ld_word(fs->win + BPB_FATSz16); + if (fasize == 0) + fasize = ld_dword(fs->win + BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; + if (fs->n_fats != 1 && fs->n_fats != 2) + return FR_NO_FILESYSTEM; + fasize *= fs->n_fats; + + fs->csize = fs->win[BPB_SecPerClus]; + if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) + return FR_NO_FILESYSTEM; + + fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); + if (fs->n_rootdir % (SS(fs) / SZDIRE)) + return FR_NO_FILESYSTEM; + + tsect = ld_word(fs->win + BPB_TotSec16); + if (tsect == 0) + tsect = ld_dword(fs->win + BPB_TotSec32); + + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); + if (nrsv == 0) + return FR_NO_FILESYSTEM; + + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); + if (tsect < sysect) + return FR_NO_FILESYSTEM; + nclst = (tsect - sysect) / fs->csize; + if (nclst == 0) + return FR_NO_FILESYSTEM; + fmt = 0; + if (nclst <= MAX_FAT32) + fmt = FS_FAT32; + if (nclst <= MAX_FAT16) + fmt = FS_FAT16; + if (nclst <= MAX_FAT12) + fmt = FS_FAT12; + if (fmt == 0) + return FR_NO_FILESYSTEM; + + fs->n_fatent = nclst + 2; + fs->volbase = bsect; + fs->fatbase = bsect + nrsv; + fs->database = bsect + sysect; + if (fmt == FS_FAT32) + { + if (ld_word(fs->win + BPB_FSVer32) != 0) + return FR_NO_FILESYSTEM; + if (fs->n_rootdir != 0) + return FR_NO_FILESYSTEM; + fs->dirbase = ld_dword(fs->win + BPB_RootClus32); + szbfat = fs->n_fatent * 4; + } + else + { + if (fs->n_rootdir == 0) + return FR_NO_FILESYSTEM; + fs->dirbase = fs->fatbase + fasize; + szbfat = (fmt == FS_FAT16) ? fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) + return FR_NO_FILESYSTEM; + +#if !FF_FS_READONLY + + fs->last_clst = fs->free_clst = 0xFFFFFFFF; + fs->fsi_flag = 0x80; +#if (FF_FS_NOFSINFO & 3) != 3 + if (fmt == FS_FAT32 && ld_word(fs->win + BPB_FSInfo32) == 1 && move_window(fs, bsect + 1) == FR_OK) + { + fs->fsi_flag = 0; + if (ld_word(fs->win + BS_55AA) == 0xAA55 && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) + { +#if (FF_FS_NOFSINFO & 1) == 0 + fs->free_clst = ld_dword(fs->win + FSI_Free_Count); +#endif +#if (FF_FS_NOFSINFO & 2) == 0 + fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); +#endif + } + } +#endif +#endif + } + + fs->fs_type = (BYTE)fmt; + fs->id = ++Fsid; + return FR_OK; +} + +static FRESULT validate( + FFOBJID *obj, + FATFS **rfs) +{ + FRESULT res = FR_INVALID_OBJECT; + + if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) + { + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) + { + res = FR_OK; + } + } + *rfs = (res == FR_OK) ? obj->fs : 0; + return res; +} + +FRESULT f_mount( + FATFS *fs, + const TCHAR *path, + BYTE opt) +{ + FATFS *cfs; + int vol; + FRESULT res; + const TCHAR *rp = path; + + vol = get_ldnumber(&rp); + if (vol < 0) + return FR_INVALID_DRIVE; + cfs = FatFs[vol]; + + if (cfs) + { + cfs->fs_type = 0; + } + + if (fs) + { + fs->fs_type = 0; + } + FatFs[vol] = fs; + + if (opt == 0) + return FR_OK; + + res = mount_volume(&path, &fs, 0); + LEAVE_FF(fs, res); +} + +FRESULT f_open( + FIL *fp, + const TCHAR *path, + BYTE mode) +{ + FRESULT res; + DIR dj; + FATFS *fs; +#if !FF_FS_READONLY + DWORD cl, bcs, clst; + LBA_t sc; + FSIZE_t ofs; +#endif + DEF_NAMBUF + + if (!fp) + return FR_INVALID_OBJECT; + + mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; + res = mount_volume(&path, &fs, mode); + if (res == FR_OK) + { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); + if (res == FR_OK) + { + if (dj.fn[NSFLAG] & NS_NONAME) + { + res = FR_INVALID_NAME; + } + } + + if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) + { + if (res != FR_OK) + { + if (res == FR_NO_FILE) + { + res = dir_register(&dj); + } + mode |= FA_CREATE_ALWAYS; + } + else + { + if (dj.obj.attr & (AM_RDO | AM_DIR)) + { + res = FR_DENIED; + } + else + { + if (mode & FA_CREATE_NEW) + res = FR_EXIST; + } + } + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) + { + { + + cl = ld_clust(fs, dj.dir); + st_dword(dj.dir + DIR_CrtTime, GET_FATTIME()); + dj.dir[DIR_Attr] = AM_ARC; + st_clust(fs, dj.dir, 0); + st_dword(dj.dir + DIR_FileSize, 0); + fs->wflag = 1; + if (cl != 0) + { + sc = fs->winsect; + res = remove_chain(&dj.obj, cl, 0); + if (res == FR_OK) + { + res = move_window(fs, sc); + fs->last_clst = cl - 1; + } + } + } + } + } + else + { + if (res == FR_OK) + { + if (dj.obj.attr & AM_DIR) + { + res = FR_NO_FILE; + } + else + { + if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) + { + res = FR_DENIED; + } + } + } + } + if (res == FR_OK) + { + if (mode & FA_CREATE_ALWAYS) + mode |= FA_MODIFIED; + fp->dir_sect = fs->winsect; + fp->dir_ptr = dj.dir; + } + + if (res == FR_OK) + { + { + fp->obj.sclust = ld_clust(fs, dj.dir); + fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); + } + fp->obj.fs = fs; + fp->obj.id = fs->id; + fp->flag = mode; + fp->err = 0; + fp->sect = 0; + fp->fptr = 0; +#if !FF_FS_READONLY + if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) + { + fp->fptr = fp->obj.objsize; + bcs = (DWORD)fs->csize * SS(fs); + clst = fp->obj.sclust; + for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) + { + clst = get_fat(&fp->obj, clst); + if (clst <= 1) + res = FR_INT_ERR; + if (clst == 0xFFFFFFFF) + res = FR_DISK_ERR; + } + fp->clust = clst; + if (res == FR_OK && ofs % SS(fs)) + { + sc = clst2sect(fs, clst); + if (sc == 0) + { + res = FR_INT_ERR; + } + else + { + fp->sect = sc + (DWORD)(ofs / SS(fs)); + } + } + } +#endif + } + + FREE_NAMBUF(); + } + + if (res != FR_OK) + fp->obj.fs = 0; + + LEAVE_FF(fs, res); +} + +FRESULT f_read( + FIL *fp, + void *buff, + UINT btr, + UINT *br) +{ + FRESULT res; + FATFS *fs; + DWORD clst; + LBA_t sect; + FSIZE_t remain; + UINT rcnt, cc, csect; + BYTE *rbuff = (BYTE *)buff; + + *br = 0; + res = validate(&fp->obj, &fs); + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) + LEAVE_FF(fs, res); + if (!(fp->flag & FA_READ)) + LEAVE_FF(fs, FR_DENIED); + remain = fp->obj.objsize - fp->fptr; + if (btr > remain) + btr = (UINT)remain; + + for (; btr; + btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) + { + if (fp->fptr % SS(fs) == 0) + { + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); + if (csect == 0) + { + if (fp->fptr == 0) + { + clst = fp->obj.sclust; + } + else + { + { + clst = get_fat(&fp->obj, fp->clust); + } + } + if (clst < 2) + ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) + ABORT(fs, FR_DISK_ERR); + fp->clust = clst; + } + sect = clst2sect(fs, fp->clust); + if (sect == 0) + ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btr / SS(fs); + if (cc > 0) + { + if (csect + cc > fs->csize) + { + cc = fs->csize - csect; + } + if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) + ABORT(fs, FR_DISK_ERR); +#if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 + if (fs->wflag && fs->winsect - sect < cc) + { + mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); + } +#endif + rcnt = SS(fs) * cc; + continue; + } + fp->sect = sect; + } + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); + if (rcnt > btr) + rcnt = btr; + if (move_window(fs, fp->sect) != FR_OK) + ABORT(fs, FR_DISK_ERR); + mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); + } + + LEAVE_FF(fs, FR_OK); +} + +#if !FF_FS_READONLY + +FRESULT f_write( + FIL *fp, + const void *buff, + UINT btw, + UINT *bw) +{ + FRESULT res; + FATFS *fs; + DWORD clst; + LBA_t sect; + UINT wcnt, cc, csect; + const BYTE *wbuff = (const BYTE *)buff; + + *bw = 0; + res = validate(&fp->obj, &fs); + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) + LEAVE_FF(fs, res); + if (!(fp->flag & FA_WRITE)) + LEAVE_FF(fs, FR_DENIED); + + if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) + { + btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); + } + + for (; btw; + btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) + { + if (fp->fptr % SS(fs) == 0) + { + csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); + if (csect == 0) + { + if (fp->fptr == 0) + { + clst = fp->obj.sclust; + if (clst == 0) + { + clst = create_chain(&fp->obj, 0); + } + } + else + { + { + clst = create_chain(&fp->obj, fp->clust); + } + } + if (clst == 0) + break; + if (clst == 1) + ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) + ABORT(fs, FR_DISK_ERR); + fp->clust = clst; + if (fp->obj.sclust == 0) + fp->obj.sclust = clst; + } + if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) + ABORT(fs, FR_DISK_ERR); + sect = clst2sect(fs, fp->clust); + if (sect == 0) + ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btw / SS(fs); + if (cc > 0) + { + if (csect + cc > fs->csize) + { + cc = fs->csize - csect; + } + if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) + ABORT(fs, FR_DISK_ERR); +#if FF_FS_MINIMIZE <= 2 + if (fs->winsect - sect < cc) + { + mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); + fs->wflag = 0; + } +#endif + wcnt = SS(fs) * cc; + continue; + } + if (fp->fptr >= fp->obj.objsize) + { + if (sync_window(fs) != FR_OK) + ABORT(fs, FR_DISK_ERR); + fs->winsect = sect; + } + fp->sect = sect; + } + wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); + if (wcnt > btw) + wcnt = btw; + if (move_window(fs, fp->sect) != FR_OK) + ABORT(fs, FR_DISK_ERR); + mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); + fs->wflag = 1; + } + + fp->flag |= FA_MODIFIED; + + LEAVE_FF(fs, FR_OK); +} + +FRESULT f_sync( + FIL *fp) +{ + FRESULT res; + FATFS *fs; + DWORD tm; + BYTE *dir; + + res = validate(&fp->obj, &fs); + if (res == FR_OK) + { + if (fp->flag & FA_MODIFIED) + { + + tm = GET_FATTIME(); + { + res = move_window(fs, fp->dir_sect); + if (res == FR_OK) + { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; + st_clust(fp->obj.fs, dir, fp->obj.sclust); + st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); + st_dword(dir + DIR_ModTime, tm); + st_word(dir + DIR_LstAccDate, 0); + fs->wflag = 1; + res = sync_fs(fs); + fp->flag &= (BYTE)~FA_MODIFIED; + } + } + } + } + + LEAVE_FF(fs, res); +} + +#endif + +FRESULT f_close( + FIL *fp) +{ + FRESULT res; + FATFS *fs; + +#if !FF_FS_READONLY + res = f_sync(fp); + if (res == FR_OK) +#endif + { + res = validate(&fp->obj, &fs); + if (res == FR_OK) + { + fp->obj.fs = 0; + } + } + return res; +} + +FRESULT f_stat( + const TCHAR *path, + FILINFO *fno) +{ + FRESULT res; + DIR dj; + DEF_NAMBUF + + res = mount_volume(&path, &dj.obj.fs, 0); + if (res == FR_OK) + { + INIT_NAMBUF(dj.obj.fs); + res = follow_path(&dj, path); + if (res == FR_OK) + { + if (dj.fn[NSFLAG] & NS_NONAME) + { + res = FR_INVALID_NAME; + } + else + { + if (fno) + get_fileinfo(&dj, fno); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(dj.obj.fs, res); +} + +FRESULT f_unlink( + const TCHAR *path) +{ + FRESULT res; + DIR dj, sdj; + DWORD dclst = 0; + FATFS *fs; + DEF_NAMBUF + + res = mount_volume(&path, &fs, FA_WRITE); + if (res == FR_OK) + { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); + if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) + { + res = FR_INVALID_NAME; + } + if (res == FR_OK) + { + if (dj.fn[NSFLAG] & NS_NONAME) + { + res = FR_INVALID_NAME; + } + else + { + if (dj.obj.attr & AM_RDO) + { + res = FR_DENIED; + } + } + if (res == FR_OK) + { + { + dclst = ld_clust(fs, dj.dir); + } + if (dj.obj.attr & AM_DIR) + { + { + sdj.obj.fs = fs; + sdj.obj.sclust = dclst; + res = dir_sdi(&sdj, 0); + if (res == FR_OK) + { + res = DIR_READ_FILE(&sdj); + if (res == FR_OK) + res = FR_DENIED; + if (res == FR_NO_FILE) + res = FR_OK; + } + } + } + } + if (res == FR_OK) + { + res = dir_remove(&dj); + if (res == FR_OK && dclst != 0) + { + res = remove_chain(&dj.obj, dclst, 0); + } + if (res == FR_OK) + res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} \ No newline at end of file diff --git a/ff.h b/ff.h new file mode 100644 index 0000000..a5483ed --- /dev/null +++ b/ff.h @@ -0,0 +1,173 @@ +#ifndef FF_DEFINED +#define FF_DEFINED 86606 + +#include "ffconf.h" + +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) +#define FF_INTDEF 2 +#include +typedef unsigned int UINT; +typedef unsigned char BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; +typedef uint64_t QWORD; +typedef WORD WCHAR; +#else +#define FF_INTDEF 1 +typedef unsigned int UINT; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef WORD WCHAR; +#endif + +#ifndef _INC_TCHAR +#define _INC_TCHAR + +typedef char TCHAR; +#define _T(x) x +#define _TEXT(x) x + +#endif +typedef DWORD FSIZE_t; +typedef DWORD LBA_t; + +typedef struct +{ + BYTE fs_type; + BYTE pdrv; + BYTE n_fats; + BYTE wflag; + BYTE fsi_flag; + WORD id; + WORD n_rootdir; + WORD csize; +#if !FF_FS_READONLY + DWORD last_clst; + DWORD free_clst; +#endif + DWORD n_fatent; + DWORD fsize; + LBA_t volbase; + LBA_t fatbase; + LBA_t dirbase; + LBA_t database; + LBA_t winsect; + BYTE win[FF_MAX_SS]; +} FATFS; + +typedef struct +{ + FATFS *fs; + WORD id; + BYTE attr; + BYTE stat; + DWORD sclust; + FSIZE_t objsize; +} FFOBJID; + +typedef struct +{ + FFOBJID obj; + BYTE flag; + BYTE err; + FSIZE_t fptr; + DWORD clust; + LBA_t sect; +#if !FF_FS_READONLY + LBA_t dir_sect; + BYTE *dir_ptr; +#endif +} FIL; + +typedef struct +{ + FFOBJID obj; + DWORD dptr; + DWORD clust; + LBA_t sect; + BYTE *dir; + BYTE fn[12]; +} DIR; + +typedef struct +{ + FSIZE_t fsize; + WORD fdate; + WORD ftime; + BYTE fattrib; + TCHAR fname[12 + 1]; +} FILINFO; + +typedef struct +{ + BYTE fmt; + BYTE n_fat; + UINT align; + UINT n_root; + DWORD au_size; +} MKFS_PARM; + +typedef enum +{ + FR_OK = 0, + FR_DISK_ERR, + FR_INT_ERR, + FR_NOT_READY, + FR_NO_FILE, + FR_NO_PATH, + FR_INVALID_NAME, + FR_DENIED, + FR_EXIST, + FR_INVALID_OBJECT, + FR_WRITE_PROTECTED, + FR_INVALID_DRIVE, + FR_NOT_ENABLED, + FR_NO_FILESYSTEM, + FR_MKFS_ABORTED, + FR_TIMEOUT, + FR_LOCKED, + FR_NOT_ENOUGH_CORE, + FR_TOO_MANY_OPEN_FILES, + FR_INVALID_PARAMETER +} FRESULT; + +FRESULT f_open(FIL *fp, const TCHAR *path, BYTE mode); +FRESULT f_close(FIL *fp); +FRESULT f_read(FIL *fp, void *buff, UINT btr, UINT *br); +FRESULT f_write(FIL *fp, const void *buff, UINT btw, UINT *bw); +FRESULT f_sync(FIL *fp); +FRESULT f_unlink(const TCHAR *path); +FRESULT f_stat(const TCHAR *path, FILINFO *fno); +FRESULT f_mount(FATFS *fs, const TCHAR *path, BYTE opt); + +#define f_size(fp) ((fp)->obj.objsize) + +#define FA_READ 0x01 +#define FA_WRITE 0x02 +#define FA_OPEN_EXISTING 0x00 +#define FA_CREATE_NEW 0x04 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA_OPEN_APPEND 0x30 + +#define CREATE_LINKMAP ((FSIZE_t)0 - 1) + +#define FM_FAT 0x01 +#define FM_FAT32 0x02 +#define FM_EXFAT 0x04 +#define FM_ANY 0x07 +#define FM_SFD 0x08 + +#define FS_FAT12 1 +#define FS_FAT16 2 +#define FS_FAT32 3 +#define FS_EXFAT 4 + +#define AM_RDO 0x01 +#define AM_HID 0x02 +#define AM_SYS 0x04 +#define AM_DIR 0x10 +#define AM_ARC 0x20 + +#endif \ No newline at end of file diff --git a/ffconf.h b/ffconf.h new file mode 100644 index 0000000..ffdcf00 --- /dev/null +++ b/ffconf.h @@ -0,0 +1,14 @@ +#define FFCONF_DEF 86606 +#define FF_FS_READONLY 0 +#define FF_FS_MINIMIZE 0 +#define FF_USE_LABEL 0 +#define FF_CODE_PAGE 932 +#define FF_USE_LFN 0 +#define FF_FS_RPATH 0 +#define FF_VOLUMES 1 +#define FF_MULTI_PARTITION 0 +#define FF_MAX_SS 512 +#define FF_FS_EXFAT 0 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2019 \ No newline at end of file diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..e608636 Binary files /dev/null and b/icon.png differ diff --git a/im01.cpp b/im01.cpp new file mode 100644 index 0000000..ba00071 --- /dev/null +++ b/im01.cpp @@ -0,0 +1,76 @@ +#include "ff.h" +#include "diskio.h" +#include "inttypes.h" +#include "pxt.h" +#include "pxtcore.h" + +namespace im01 +{ + +//% +void _mkdir(String s) +{ +} + +//% +void _remove(String s) +{ + FATFS FatFs; + f_mount(&FatFs, "", 0); + f_unlink((const char *)s->getUTF8Data()); +} + +//% +bool _file(String s, String v, uint8_t x) +{ + FATFS FatFs; + f_mount(&FatFs, "", 0); + FIL Fil; + UINT bw; + FRESULT fr; + fr = f_open(&Fil, (const char *)s->getUTF8Data(), x); + if (fr == FR_OK) + { + f_write(&Fil, (const char *)v->getUTF8Data(), v->getUTF8Size(), &bw); + fr = f_close(&Fil); + if (fr == FR_OK && bw == v->getUTF8Size()) + { + return true; + } + return false; + } + return false; +} + +//% +uint32_t _size(String s) +{ + FATFS FatFs; + f_mount(&FatFs, "", 0); + uint32_t lSize = 0; + FIL Fil; + FRESULT fr; + fr = f_open(&Fil, (const char *)s->getUTF8Data(), FA_READ | FA_WRITE); + lSize = f_size(&Fil); + f_close(&Fil); + return lSize; +} + +//% +bool _exists(String s) +{ + FATFS FatFs; + f_mount(&FatFs, "", 0); + FRESULT fr; + FILINFO fno; + fr = f_stat((const char *)s->getUTF8Data(), &fno); + if (fr == FR_OK) + return true; + return false; +} + +//% +String _read(String s) +{ +} +} // namespace cs11 \ No newline at end of file diff --git a/im01.ts b/im01.ts new file mode 100644 index 0000000..42b9944 --- /dev/null +++ b/im01.ts @@ -0,0 +1,131 @@ +//%color=#444444 icon="\uf07b" +namespace IM01 { + let sdFlag = false + //%block="IM01 size of file %u" + //%u.defl="log.txt" + function sizeOfFile(u: string): number { + u = truncateStringLength(u) + if (sdFlag == false) { + createFolder("CS11") + sdFlag = true + } + return size(u) + } + + //%block="IM01 remove file" + //%u.defl="log.txt" + export function removeFile(u: string): void { + u = truncateStringLength(u) + if (sdFlag == false) { + createFolder("CS11") + sdFlag = true + } + remove(u) + return + } + + //%block="IM01 file %u exists" + //%u.defl="log.txt" + export function fileExists(u: string): boolean { + u = truncateStringLength(u) + if (sdFlag == false) { + createFolder("CS11") + sdFlag = true + } + return exists(u) + } + + //%block="IM01 overwrite file %u with %v" + //%u.defl="log.txt" + export function overwriteFile(u: string, v: string): void { + u = truncateStringLength(u) + if (sdFlag == false) { + createFolder("CS11") + sdFlag = true + } + file(u, v, 0x02 | 0x08) + return + } + + //%block="IM01 append file %u with %v" + //%u.defl="log.txt" + export function appendFile(u: string, v: string): void { + u = truncateStringLength(u) + if (sdFlag == false) { + createFolder("CS11") + sdFlag = true + } + file(u, v, 0x02 | 0x30) + return + } + + //%block="IM01 append file %u with line %v" + //%u.defl="log.txt" + export function appendFileLine(u: string, v: string): void { + u = truncateStringLength(u) + if (sdFlag == false) { + createFolder("CS11") + sdFlag = true + } + file(u, v + "\n", 0x02 | 0x30) + return + } + + //%block="IM01 read file %u" + //%u.defl="log.txt" + export function readFile(u: string): string { + u = truncateStringLength(u) + if (sdFlag == false) { + createFolder("CS11") + sdFlag = true + } + return file_read(u) + } + + //%block="IM01 create folder %u" + function createFolder(u: string): void { + mkdir(u) + return; + } + + //%shim=im01::_mkdir + function mkdir(u: string): void { + return + } + + //%shim=im01::_remove + function remove(u: string): void { + return + } + + //%shim=im01::_file + function file(u: string, v: string, x: number): boolean { + return true + } + + //%shim=im01::_size + function size(u: string): number { + return 1 + } + + //%shim=im01::_exists + function exists(u: string): boolean { + return true + } + + //%shim=im01::_read + function file_read(u: string): string { + return "" + } + + function truncateStringLength(u: string): string { + let i = u.indexOf(".") + let ext = u.substr(i, u.length) + if (i > 8) { + u = u.substr(0, 8) + ext + } + return u + } + + +} \ No newline at end of file diff --git a/main.blocks b/main.blocks deleted file mode 100644 index fd0869b..0000000 --- a/main.blocks +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/main.ts b/main.ts deleted file mode 100644 index ee54a1b..0000000 --- a/main.ts +++ /dev/null @@ -1,3 +0,0 @@ -basic.forever(function () { - -}) diff --git a/pxt.json b/pxt.json index 2163bd2..8f105e4 100644 --- a/pxt.json +++ b/pxt.json @@ -1,22 +1,32 @@ { - "name": "pxt-im01-2", - "version": "0.0.1", - "description": "", + "name": "CS11", + "version": "0.0.8", + "description": "XinaBox CS11 SD Card: SD Card functionality.", + "license": "MIT", "dependencies": { - "core": "*", - "radio": "*" + "core": "*" }, "files": [ "README.md", - "main.blocks", - "main.ts" + "main.ts", + "sdmm.cpp", + "im01.ts", + "im01.cpp", + "diskio.h", + "ff.cpp", + "ff.h", + "ffconf.h" ], "testFiles": [ "test.ts" ], "public": true, "supportedTargets": [ - "microbit" + "maker" ], - "preferredEditor": "tsprj" + "preferredEditor": "blocksprj", + "authors": [ + "Luqmaan Baboo", + "Bjarke Gotfredsen" + ] } diff --git a/sdmm.cpp b/sdmm.cpp new file mode 100644 index 0000000..5194ab0 --- /dev/null +++ b/sdmm.cpp @@ -0,0 +1,544 @@ +#include "ff.h" +#include "diskio.h" + +#include "pxt.h" + + +/* + MISO = P14 + MOSI = P15 + SCK = P13 + CS = P16 +*/ + + +void DO_INIT() +{ + + uBit.io.P14.setDigitalValue(0); +} + + +bool DO() +{ + + return uBit.io.P14.getDigitalValue(); +} + +void DI_INIT() +{ + + uBit.io.P15.setDigitalValue(0); +} + +void DI_H() +{ + + uBit.io.P15.setDigitalValue(1); +} +void DI_L() +{ + + uBit.io.P15.setDigitalValue(0); +} + +void CK_INIT() +{ + + uBit.io.P13.setDigitalValue(0); +} +void CK_H() +{ + + uBit.io.P13.setDigitalValue(1); +} +void CK_L() +{ + + uBit.io.P13.setDigitalValue(0); +} + +void CS_INIT() +{ + + uBit.io.P16.setDigitalValue(0); +} +void CS_H() +{ + + uBit.io.P16.setDigitalValue(1); +} +void CS_L() +{ + + uBit.io.P16.setDigitalValue(0); +} + +void dly_us(UINT n) +{ + sleep_us(n); +} + +#define CMD0 (0) +#define CMD1 (1) +#define ACMD41 (0x80 + 41) +#define CMD8 (8) +#define CMD9 (9) +#define CMD12 (12) +#define CMD16 (16) +#define CMD17 (17) +#define CMD18 (18) +#define ACMD23 (0x80 + 23) +#define CMD24 (24) +#define CMD25 (25) +#define CMD55 (55) +#define CMD58 (58) + +static DSTATUS Stat = STA_NOINIT; + +static BYTE CardType; + +static void xmit_mmc( + const BYTE *buff, + UINT bc) +{ + BYTE d; + + do + { + d = *buff++; + if (d & 0x80) + DI_H(); + else + DI_L(); + CK_H(); + CK_L(); + if (d & 0x40) + DI_H(); + else + DI_L(); + CK_H(); + CK_L(); + if (d & 0x20) + DI_H(); + else + DI_L(); + CK_H(); + CK_L(); + if (d & 0x10) + DI_H(); + else + DI_L(); + CK_H(); + CK_L(); + if (d & 0x08) + DI_H(); + else + DI_L(); + CK_H(); + CK_L(); + if (d & 0x04) + DI_H(); + else + DI_L(); + CK_H(); + CK_L(); + if (d & 0x02) + DI_H(); + else + DI_L(); + CK_H(); + CK_L(); + if (d & 0x01) + DI_H(); + else + DI_L(); + CK_H(); + CK_L(); + } while (--bc); +} + +static void rcvr_mmc( + BYTE *buff, + UINT bc) +{ + BYTE r; + + DI_H(); + + do + { + r = 0; + if (DO()) + r++; + CK_H(); + CK_L(); + r <<= 1; + if (DO()) + r++; + CK_H(); + CK_L(); + r <<= 1; + if (DO()) + r++; + CK_H(); + CK_L(); + r <<= 1; + if (DO()) + r++; + CK_H(); + CK_L(); + r <<= 1; + if (DO()) + r++; + CK_H(); + CK_L(); + r <<= 1; + if (DO()) + r++; + CK_H(); + CK_L(); + r <<= 1; + if (DO()) + r++; + CK_H(); + CK_L(); + r <<= 1; + if (DO()) + r++; + CK_H(); + CK_L(); + *buff++ = r; + } while (--bc); +} + +static int wait_ready(void) +{ + BYTE d; + UINT tmr; + + for (tmr = 5000; tmr; tmr--) + { + rcvr_mmc(&d, 1); + if (d == 0xFF) + break; + dly_us(100); + } + + return tmr ? 1 : 0; +} + +void deselect(void) +{ + BYTE d; + + CS_H(); + rcvr_mmc(&d, 1); +} + +static int select(void) +{ + BYTE d; + + CS_L(); + rcvr_mmc(&d, 1); + if (wait_ready()) + return 1; + + deselect(); + return 0; +} + +static int rcvr_datablock( + BYTE *buff, + UINT btr) +{ + BYTE d[2]; + UINT tmr; + + for (tmr = 1000; tmr; tmr--) + { + rcvr_mmc(d, 1); + if (d[0] != 0xFF) + break; + dly_us(100); + } + if (d[0] != 0xFE) + return 0; + + rcvr_mmc(buff, btr); + rcvr_mmc(d, 2); + + return 1; +} + +static int xmit_datablock( + const BYTE *buff, + BYTE token) +{ + BYTE d[2]; + + if (!wait_ready()) + return 0; + + d[0] = token; + xmit_mmc(d, 1); + if (token != 0xFD) + { + xmit_mmc(buff, 512); + rcvr_mmc(d, 2); + rcvr_mmc(d, 1); + if ((d[0] & 0x1F) != 0x05) + return 0; + } + + return 1; +} + +static BYTE send_cmd( + BYTE cmd, + DWORD arg) +{ + BYTE n, d, buf[6]; + + if (cmd & 0x80) + { + cmd &= 0x7F; + n = send_cmd(CMD55, 0); + if (n > 1) + return n; + } + + if (cmd != CMD12) + { + deselect(); + if (!select()) + return 0xFF; + } + + buf[0] = 0x40 | cmd; + buf[1] = (BYTE)(arg >> 24); + buf[2] = (BYTE)(arg >> 16); + buf[3] = (BYTE)(arg >> 8); + buf[4] = (BYTE)arg; + n = 0x01; + if (cmd == CMD0) + n = 0x95; + if (cmd == CMD8) + n = 0x87; + buf[5] = n; + xmit_mmc(buf, 6); + + if (cmd == CMD12) + rcvr_mmc(&d, 1); + n = 10; + do + rcvr_mmc(&d, 1); + while ((d & 0x80) && --n); + + return d; +} + +DSTATUS disk_status( + BYTE drv) +{ + if (drv) + return STA_NOINIT; + + return Stat; +} + +DSTATUS disk_initialize( + BYTE drv) +{ + BYTE n, ty, cmd, buf[4]; + UINT tmr; + DSTATUS s; + + if (drv) + return RES_NOTRDY; + + dly_us(10000); + CS_INIT(); + CS_H(); + CK_INIT(); + CK_L(); + DI_INIT(); + DO_INIT(); + + for (n = 10; n; n--) + rcvr_mmc(buf, 1); + + ty = 0; + if (send_cmd(CMD0, 0) == 1) + { + if (send_cmd(CMD8, 0x1AA) == 1) + { + rcvr_mmc(buf, 4); + if (buf[2] == 0x01 && buf[3] == 0xAA) + { + for (tmr = 1000; tmr; tmr--) + { + if (send_cmd(ACMD41, 1UL << 30) == 0) + break; + dly_us(1000); + } + if (tmr && send_cmd(CMD58, 0) == 0) + { + rcvr_mmc(buf, 4); + ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; + } + } + } + else + { + if (send_cmd(ACMD41, 0) <= 1) + { + ty = CT_SD1; + cmd = ACMD41; + } + else + { + ty = CT_MMC; + cmd = CMD1; + } + for (tmr = 1000; tmr; tmr--) + { + if (send_cmd(cmd, 0) == 0) + break; + dly_us(1000); + } + if (!tmr || send_cmd(CMD16, 512) != 0) + ty = 0; + } + } + CardType = ty; + s = ty ? 0 : STA_NOINIT; + Stat = s; + + deselect(); + + return s; +} + +DRESULT disk_read( + BYTE drv, + BYTE *buff, + LBA_t sector, + UINT count) +{ + BYTE cmd; + DWORD sect = (DWORD)sector; + + if (disk_status(drv) & STA_NOINIT) + return RES_NOTRDY; + if (!(CardType & CT_BLOCK)) + sect *= 512; + + cmd = count > 1 ? CMD18 : CMD17; + if (send_cmd(cmd, sect) == 0) + { + do + { + if (!rcvr_datablock(buff, 512)) + break; + buff += 512; + } while (--count); + if (cmd == CMD18) + send_cmd(CMD12, 0); + } + deselect(); + + return count ? RES_ERROR : RES_OK; +} + +DRESULT disk_write( + BYTE drv, + const BYTE *buff, + LBA_t sector, + UINT count) +{ + DWORD sect = (DWORD)sector; + + if (disk_status(drv) & STA_NOINIT) + return RES_NOTRDY; + if (!(CardType & CT_BLOCK)) + sect *= 512; + + if (count == 1) + { + if ((send_cmd(CMD24, sect) == 0) && xmit_datablock(buff, 0xFE)) + count = 0; + } + else + { + if (CardType & CT_SDC) + send_cmd(ACMD23, count); + if (send_cmd(CMD25, sect) == 0) + { + do + { + if (!xmit_datablock(buff, 0xFC)) + break; + buff += 512; + } while (--count); + if (!xmit_datablock(0, 0xFD)) + count = 1; + } + } + deselect(); + + return count ? RES_ERROR : RES_OK; +} + +DRESULT disk_ioctl( + BYTE drv, + BYTE ctrl, + void *buff) +{ + DRESULT res; + BYTE n, csd[16]; + DWORD cs; + + if (disk_status(drv) & STA_NOINIT) + return RES_NOTRDY; + + res = RES_ERROR; + switch (ctrl) + { + case CTRL_SYNC: + if (select()) + res = RES_OK; + break; + + case GET_SECTOR_COUNT: + if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) + { + if ((csd[0] >> 6) == 1) + { + cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; + *(LBA_t *)buff = cs << 10; + } + else + { + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; + *(LBA_t *)buff = cs << (n - 9); + } + res = RES_OK; + } + break; + + case GET_BLOCK_SIZE: + *(DWORD *)buff = 128; + res = RES_OK; + break; + + default: + res = RES_PARERR; + } + + deselect(); + + return res; +}